Why exactly is emptiness asynchronous?
So, I understand why returning void from async usually doesn't make any sense, but I ran into a situation where I think it would be perfectly correct. Consider the following contrived example:
protected override void OnLoad(EventArgs e)
{
if (CustomTask == null)
// Do not await anything, let OnLoad return.
PrimeCustomTask();
}
private TaskCompletionSource<int> CustomTask;
// I DO NOT care about the return value from this. So why is void bad?
private async void PrimeCustomTask()
{
CustomTask = new TaskCompletionSource<int>();
int result = 0;
try
{
// Wait for button click to set the value, but do not block the UI.
result = await CustomTask.Task;
}
catch
{
// Handle exceptions
}
CustomTask = null;
// Show the value
MessageBox.Show(result.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
if (CustomTask != null)
CustomTask.SetResult(500);
}
I realize this is an unusual example, but I tried to make it simpler and more general. Can someone please explain to me why this is terrible code and also how can I change it to follow the rules correctly?
Thanks for any help.
source to share
Ok, following the reasons in the "avoid async void
" article :
- Asynchronous void methods have different error handling semantics. Exceptions from
PrimeCustomTask
will be very inconvenient to handle. - Asynchronous methods have different semantics. This is a maintainability and code reuse oriented argument. In fact, the logic is in
PrimeCustomTask
there and that it is - it cannot be compiled into a higher levelasync
. - Asynchronous invalid methods are difficult to test. Naturally from the first two points it is very difficult to write a unit test coverage
PrimeCustomTask
(or whatever calls it).
It's also important to note that async Task
is a natural approach. Of the several languages ββthat have adopted async
/await
, C # / VB are the only ones AFAIK that support async void
at all. F # doesn't, Python doesn't, JavaScript and TypeScript don't. async void
is unnatural in terms of language design.
The reason async void
was added to C # / VB to enable asynchronous event handlers. If you change your code to use event handlers async void
:
protected override async void OnLoad(EventArgs e)
{
if (CustomTask == null)
await PrimeCustomTask();
}
private async Task PrimeCustomTask()
Then the disadvantages are async void
limited to your event handler. In particular, exceptions from PrimeCustomTask
naturally propagate to its (asynchronous) callers ( OnLoad
), PrimeCustomTask
can be composed (naturally called by other asynchronous methods), and PrimeCustomTask
much easier to include in a unit test.
source to share