by Andreas Hallberg - .Net, Tips & Tricks
Executing code asynchronously in C# gives you at least two headaches: the code becomes hard to read and a pain to unit test.
Here’s one way to alleviate these pains, using a configurable singleton aptly named “Async”:
|
1 2 3 4 5 6 |
<span style="color: #2b91af;">Async</span>.Execute(() => { <span style="color: green;">// ... </span><span style="color: #2b91af;">Console</span>.WriteLine(<span style="color: #a31515;">"We're running this on a background thread"</span>); <span style="color: green;">// ... etc </span>}); |
That’s the readability headache removed. Here’s how we implement the Async class:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<span style="color: blue;">public class </span><span style="color: #2b91af;">Async </span>{ <span style="color: blue;"> private static </span><span style="color: #2b91af;">IAsyncExecutor </span>theAsyncExecutor; <span style="color: blue;">public static void </span>Configure(<span style="color: #2b91af;">IAsyncExecutor </span>asyncExecutor) { theAsyncExecutor = asyncExecutor; } <span style="color: blue;">public static void </span>Execute(<span style="color: #2b91af;">Action </span>a) { theAsyncExecutor.Execute(a); } } <span style="color: blue;">public interface </span><span style="color: #2b91af;">IAsyncExecutor </span>{ <span style="color: blue;"> void </span>Execute(<span style="color: #2b91af;">Action </span>a); } |
You need to configure Async with a concrete IAsyncExecutor. A ThreadPool implementation is one solution for Silverlight/WPF/WinForms:
|
1 2 3 4 5 6 7 |
<span style="color: blue;">public class </span><span style="color: #2b91af;">ThreadPoolAsyncExecutor </span>: <span style="color: #2b91af;">IAsyncExecutor </span>{ <span style="color: blue;">public void </span>Execute(<span style="color: #2b91af;">Action </span>a) { <span style="color: #2b91af;">ThreadPool</span>.QueueUserWorkItem(x => a()); } } |
That’s actually not too messy, but let’s agree that “Async.Execute” is easier on the eyes than “ThreadPool.QueueUserWorkItem”.
What about the testing-headache? Get instant relief by configuring Async with a fake IAsyncExecutor before you run your unittests:
|
1 2 3 4 5 6 7 |
<span style="color: blue;">public class </span><span style="color: #2b91af;">FakeAsyncExecutor </span>: <span style="color: #2b91af;">IAsyncExecutor </span>{ <span style="color: blue;">public void </span>Invoke(<span style="color: #2b91af;">Action </span>a) { a(); } } |
Cheating, you say? Well, do we really need to assert that the code is being run on a background thread? More likely we just want assert that it does what it’s supposed to do, regardless of which thread it runs on. But, if you indeed want to assert that the class does some task in the background, you can assert that the Execute method is being called on your fake/mock IAsyncExecutor.
Now all we need to do is learn how to reliably spell asynchrounu… asynchronus… yeah.
Hope this helps,
Love the simplicity!
Kudos
[...] Readable and testable asynchronous execution – Andreas Hallberg shares a simple helper class which makes writing Async code cleaner, and provides an implementation which can be easily replaced for testing to remove the async nature. [...]