Should I avoid 'async void' event handlers?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
When working with asynchronous programming in C#, one of the questions that arise frequently is whether or not to use async void event handlers. At first glance, async void functions might appear simple and beneficial, especially in GUI applications where event-driven actions are dominant. However, they bring certain complexities and risks. This article delves into when and why you might need to avoid async void event handlers, offering technical insights, examples, and alternatives.
Understanding Async/Await in C#
Before discussing async void, it's important to understand the basics of async and await in C#.
Asynchronous Methods
Asynchronous programming is aimed at improving the scalability and performance of applications by running tasks concurrently, thus avoiding the blocking of the main execution flow. In C#, asynchronous methods are typically declared with the async keyword and usually return Task or Task<TResult>.
Here, the await keyword pauses the execution of SampleAsyncMethod until the Task.Delay is completed. The method returns a Task that represents the asynchronous operation.
The Peculiar Nature of Async Void
What is Async Void?
An async void method in C# is an asynchronous method that returns no value and completes at some point after the control returns from the function. Here’s a simple example of an async void method in the context of an event handler:
In this example, the method is tied to a button click event and is asynchronous.
Why You Might Want to Avoid Async Void
- Error Propagation: One of the main issues with
async voidis error handling. Unlike methods that returnTask, exceptions thrown within anasync voidmethod cannot be awaited, which means they propagate directly to theSynchronizationContext. This bypasses the ability to usetry-catchblocks directly around the calling code. - Non-deterministic Completion:
async voidmethods run asynchronously without aTask, making it difficult to determine when they have completed. This can lead to race conditions or unpredictable behavior in application logic. - Debugging Challenges: When an exception occurs in an
async voidmethod, the call stack is typically less informative, because the context of the error is not retained in the same way as inTask-based asynchronous methods. - Testability Issues: Since unit tests usually rely on the task returning methods,
async voidmethods pose a challenge for testing frameworks that await task completion.
When to Use Async Void
Despite the highlighted drawbacks, there are specific scenarios where async void is justifiable:
- Event Handlers: Due to the signature requirements of .NET event handlers (
void EventHandlerMethodName(object sender, EventArgs e)),async voidis often used. This is typically the only place whereasync voidis considered acceptable.
Recommendations and Best Practices
To mitigate the downsides of async void methods, consider these best practices:
- Avoid Direct Use: Whenever possible, prefer methods that return
TaskorTask<TResult>. This offers better error handling, testability, and maintainability. - Wrap Async Logic in Task Returning Functions:For long-running operations that might originally use
async void, consider wrapping the logic in a method that returns aTask:
- Use Exception Handling: Be especially mindful of potential exceptions within
async voidevent handlers, and handle them where applicable to preserve application stability.
Summary of Key Points
Below is a table summarizing the key points about async void:
| Aspect | Async Task | Async Void |
| Return Type | Task or Task<TResult> | void |
| Error Handling | Propagated with await and try-catch blocks | Directly to Synchronization Context (exceptions often crash the application if unhandled) |
| Completion Tracking | Can be awaited for completion | Non-deterministic |
| Use Cases | General asynchronous programming | Event handlers |
| Testability | Easy to test with await | Harder, often avoidable |
Conclusion
While async void seems convenient, especially in UI event handling scenarios, it inherently lacks the robustness provided by asynchronous Task-based methods. By understanding its nuances and applying best practices, developers can avoid common pitfalls, maintain cleaner code, and build applications that are more stable and easier to maintain.
Related reading
- Should I avoid 'async void' event handlers?
- Should I be using process.nextTick
- Should I offload work to other threads in ASP.NET?
- Should I use async all the way for my GUI app?
- Should I bind to ICollectionView or ObservableCollection
- Should I derive custom exceptions from Exception or ApplicationException in .NET?
- Should i use ThreadPools or Task Parallel Library for IO-bound operations
- Should I worry about This async method lacks 'await' operators and will run synchronously warning

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.