Event handlers and void returning async methods

Async methods can be built from other async methods using await. But where does the asynchrony end? What kind of top level synchronous methods call asynchronous ones to start with?

In a client application the typical answer is that asynchronous operations are set off by events. The user clicks a button, and an asynchronous activity is set in motion that keeps trickling little chunks of work onto the UI thread in between awaits, until it is finally done. The event itself does not care when the asynchronous operation is done – in fact no-one does. It is what we call “fire and forget.”

To accommodate this pattern, async methods can be explicitly written to be fire and forget – by returning void instead of Task or Task<TResult>. This lets the method have a signature that allows it to be signed up directly as an event handler. When a void async method runs, no Task is produced and returned, and it is therefore not possible for the caller to track its completion.

private async void sumButton_Click(object sender, RoutedEventArgs e) {
    sumButton.IsEnabled = false;
    await SumPageSizesAsync(GetUrls()));
    sumButton.IsEnabled = true;
}
Private Async Sub sumButton_Click(sender As Object, e As RoutedEventArgs)
    sumButton.IsEnabled = False
    Await SumPageSizesAsync(GetUrls())
    sumButton.IsEnabled = True
End Sub

Often the UI needs to change for the duration of an operation caused by a user event. In this case for instance, the button clicked is temporarily disabled. The very natural and symmetric pattern of just enclosing the core operation in the code to change the UI and change it back is possible now only because of await.

One Comment