Должен ли я избегать обработчиков событий async void?

Я знаю, что, как правило, плохая идея использовать методы fire-and-забыть async void для запуска задач, потому что нет пути к ожидающей задаче, и сложно обрабатывать исключения, которые могут быть выбраны внутри такого метод.

Должен ли я вообще избегать обработчиков событий async void? Например,

private async void Form_Load(object sender, System.EventArgs e)
{
        await Task.Delay(2000); // do async work
        // ...
} 

Я могу переписать его вот так:

Task onFormLoadTask = null; // track the task, can implement cancellation

private void Form_Load(object sender, System.EventArgs e)
{
        this.onFormLoadTask = OnFormLoadTaskAsync(sender, e);
} 

private async Task OnFormLoadTaskAsync(object sender, System.EventArgs e)
{
        await Task.Delay(2000); // do async work
        // ...
} 

Каковы подводные камни для асинхронных обработчиков событий, помимо возможного повторного входа?

Ответ 1

Рекомендация состоит в том, чтобы избежать async void, кроме случаев, когда используется в обработчике событий, поэтому использование async void в обработчике событий в порядке.

Тем не менее, по соображениям модульного тестирования мне часто нравится классифицировать логику всех методов async void. Например.

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);
}

Ответ 2

Должен ли я вообще избегать обработчиков событий async void?

В общем случае обработчики событий - это тот случай, когда метод aoid void не является потенциальным запахом кода.

Теперь, если вам почему-то нужно отследить задание, то техника, которую вы описываете, вполне разумна.

Ответ 3

Да, обычно async void обработчиков событий - единственный случай. Если вы хотите узнать больше об этом, вы можете посмотреть отличное видео здесь, на канале 9

The only case where this kind of fire-and-forget is appropriate is in top-level event-handlers. Every other async method in your code should return "async Task".

вот ссылка

Ответ 4

Если вы используете ReSharper, вам может быть полезно бесплатное ReCommended Extension. Он анализирует методы "асинхронные пустоты" и выделяет их при неправильном использовании. Расширение может различать различные применения async void и предоставлять описанные здесь быстрые исправления: ReCommended-Extension wiki.