Recently I was introduced to existing code base that needed some new features implemented. What caught my attention is how the person who wrote it was creating threads (and by that I literally mean creating new threads, not using threads from thread pool) like a madman. When something was needed to be updated on the UI with a certain delay, a new thread was created then immediately put to sleep and then some UI code was scheduled back on the UI thread.
Something like this:
Thread thread = new Thread(() =>
{
Thread.Sleep(1000);
Dispatcher.Invoke(() =>
{
lbItems.UnselectAll();
});
});
thread.Start();
As threads are really expensive resources, I wrote a couple of async extension methods to Action type delegate for refactoring these occurrences.
publicstaticasync Task RunDelayed(this Action action, Int32 delay) { await Task.Delay(delay); action(); } publicstaticasyncTask RunRepeated(this Action action, Int32 period, CancellationToken token, Int32 delay = 0) { if (delay > 0) await Task.Delay(delay); while (true) { if (token.IsCancellationRequested) break; action(); await Task.Delay(period); } } publicstaticasync Task RunUntil(this Action action, Func<bool> until, Int32 period, Int32 delay = 0) { if (delay > 0) await Task.Delay(delay); while (until() == false) { action(); await Task.Delay(period); } }
The first one is used for a single delayed execution and the second one runs repeated. It also accepts a CancellationToken if the loop needs to be ended.
The last one can be used to run something repeatedly, until a certain condition is met.
So now the example from the start of the post can be written as easy as this:
Action action = new Action(() => lbItems.UnselectAll());
await action.RunDelayed(1000);
No unnecessary threads and no need to schedule it back on the UI thread (if called from UI thread).
Happy coding!