Best practices
Avoid async void
-
The only place where you can safely use
async void
is 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
async
call completes, it waits for theSynchronizationContext
to become available. However, the event handler holds on to theSynchronizationContext
while it is waiting forSomeFuncAsync
method 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 void
method will be raised directly on theSynchronizationContext
that was active when theasync void
method 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 void
methods don’t provide an easy way to notify the calling code that they’ve completed -
async void
methods are difficult to test. MSTest asynchronous testing support only works forasync
methods returningTask
orTask<T>
.