Why should you avoid `async void`?
Quick Answer
async void can't be awaited, so callers can't know when it finishes or catch its exceptions — an unhandled exception in an async void method crashes the process (it's raised on the sync context). Only use it for event handlers, which the framework requires; otherwise return Task.
The problem with async void is that nothing can await it, so the caller has no idea when it's done and — more importantly — can't catch its exceptions. An unhandled exception in an async void method doesn't get captured in a Task; it gets thrown on the synchronization context and usually takes the process down. So the only legitimate use is an event handler, where the signature has to be void. Even then I wrap the body in a try/catch. Anything else returns Task.
async Task— awaitable, exceptions captured in the returnedTask, testable.async void— no way to await; exceptions propagate to theSynchronizationContextand typically become an unhandled exception.- Event handlers must be
voidto match the delegate — keep them thin:async void Button_Click(...) { try { await DoWorkAsync(); } catch { ... } }. - “Fire and forget” should still return
Taskand be handled deliberately (e.g._ = DoWorkAsync().ContinueWith(LogFailures)), notasync void.