Should I avoid 'async void' event handlers?
The guideline is to avoid async void
except when used in an event handler, so using async void
in an event handler is OK.
That said, for unit testing reasons I often like to factor out the logic of all async void
methods. E.g.,
public async Task OnFormLoadAsync(object sender, EventArgs e)
{
await Task.Delay(2000);
...
}
private async void Form_Load(object sender, EventArgs e)
{
await OnFormLoadAsync(sender, e);
}
async void event handlers - clarification?
The articles you link to make the reasons pretty clear. Don't use it because it isn't reliable beyond the most basic of scenarios. There is only so much async tracking trickery we can pull in the synchronization context on async void methods. We did work to make those basic scenarios work, but our general guidance is to avoid using them and instead explicitly register async work.
How to handle the case that the progeam needs to exit before an async void event handler finishes?
You can subscribe Window.Closing event and set e.Cancel
to true
if async event handler is running.
public partial class MainWindow : Window
{
//Flag indicating async operation is in progress
private bool m_EventHandlerIsRunning = false;
public MainWindow()
{
InitializeComponent();
}
// Subscribe this method to MainWindow's Closing event
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// Forbid MainWindow to close, if async event handler is running
e.Cancel = m_EventHandlerIsRunning;
}
// You will have to include following in all async event handlers
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
// Forbid MainWindow to be closed
m_EventHandlerIsRunning = true;
// Do something async
await Task.Delay(1000);
}
finally
{
// Let MainWindow to be closed
m_EventHandlerIsRunning = false;
}
}
}
But your application must be able to recover from such situations (where clean-up code is not executed) anyway, because there is no way for you to prevent OS crash or power outage, that can occur at anytime.
One line fire and forget: void vs. async void + await
My understanding is that adding async void and await in this case would just be useless overhead.
No.
If Handler
returned a Task
, then that would be true and eliding async
/await
would be fine; the code without async
/await
would just return the Task
directly instead of "unwrapping" it with await
and "wrapping" it back into a Task
with async
.
However, that's not the case here; Handler
returns void
, so the code without async
/await
will just ignore the returned Task
, which is wrong the vast majority of the time (hence the compiler warning). Specifically, ignoring the Task
will ignore any exceptions from that Task
. It's also not possible for your code to know when an ignored Task
has completed, but presumably that's acceptable since your handler is returning void
.
There is a "registration" that async void
methods do so that the framework is aware there is a task still in progress, so the framework knows when it's safe to shut down. The only .NET provided framework that actually cares about that is ASP.NET pre-Core; all other .NET-provided frameworks (including all UI frameworks) ignore that "registration".
Use cases for async void methods, revisited
How does the Framework keep track of pending async void methods, including event handlers?
The framework doesn't do anything special to keep track of async void methods. They're just like any other async method.
Also, your method either has a proper signature or it doesn't; event handlers do not care and have no logic to detect or work with async specifically.
A custom scheduler would be able to keep track of running tasks, but not have any specific knowledge if one is from an async void method or not. I don't think this is the right solution anyway -- if you find yourself needing to keep track of an async void method, you need to rethink your design.
Are they any useful for fire-and-forget logging scenarios? I think they actually may be, as long as the correct time-stamp is preserved
I don't know what you mean by a timestamp?
Async void is fine for any method where the caller will either never need to care about the result of the method call, or where it is being notified of the result elsewhere. These cases should be very exceedingly rare.
Fire-and-forget might be one such scenario, though I feel people often misuse fire-and-forget and end up just hiding important bugs from themselves.
Related Topics
How to Divide Two Integers to Get a Double
Json.Net Parser *Seems* to Be Double Serializing My Objects
Error: "An Object Reference Is Required For the Non-Static Field, Method or Property..."
Still Confused About Covariance and Contravariance & In/Out
Resizing an Image Without Losing Any Quality
Translucent Circular Control With Text
How to Get Httpcontext.Current in ASP.NET Core
How to Make Calls to a Rest API Using C#
How to Add a New Row to Datagridview Programmatically
Serialport Not Receiving Any Data
Why Can't I Define a Default Constructor For a Struct in .Net
C# Constructor Execution Order
What Is App.Config in C#.Net - How to Use It
Display Lines Number in Stack Trace For .Net Assembly in Release Mode