Best practices
Avoid async void
-
The only place where you can safely use
async voidis in event handlers. Consider the following code:private async Task<bool> SomeFuncAsync() { ... await ... } public void button1_Click(object sender, EventArgs e) { var result = SomeFuncAsync().Result; SomeOtherFunc(); }Once the
asynccall completes, it waits for theSynchronizationContextto become available. However, the event handler holds on to theSynchronizationContextwhile it is waiting forSomeFuncAsyncmethod to complete; thus causing a circular wait (deadlock).To fix this we need to modify the event handler to:
public async void button1_Click(object sender, EventArgs e) { var result = await SomeFuncAsync(); SomeOtherFunc(); } -
Any exception thrown out of an
async voidmethod will be raised directly on theSynchronizationContextthat was active when theasync voidmethod started.private async void SomeFuncAsync() { throw new InvalidOperationException(); } public void SomeOtherFunc() { try { SomeFuncAsync(); } catch (Exception ex) { Console.WriteLine(ex); throw; } }the exception is never caught by the catch block in
SomeOtherFunc. -
async voidmethods don’t provide an easy way to notify the calling code that they’ve completed -
async voidmethods are difficult to test. MSTest asynchronous testing support only works forasyncmethods returningTaskorTask<T>.