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

#c# #asynchronous #event-handling

#c# #.net #Мероприятия #асинхронный #async-await

Вопрос:

Я знаю, что обычно считается плохой идеей использовать методы «запустить и забыть 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, уже требуются обработчиками событий пользовательского интерфейса.

2. И повторный вход происходит из-за асинхронных операций, выполняемых обработчиком событий, а не из-за использования самого async-await .

Ответ №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);
}
 

Комментарии:

1. Мне любопытно… есть ли причина, по которой вы просто не меняете Form_Load доступ к public ? Похоже, что таким образом код будет менее подробным.

2. Упс, неважно… VBer пытается прочитать C # здесь… Я только что заметил возвращаемый тип OnFormLoadAsync . Теперь я вижу, что это делает удобный трюк. Спасибо.

3. @Alexhopeo’Connor: Handled флаг должен быть установлен синхронно; его невозможно использовать async для принятия решения о том, обрабатывается событие или нет.

4. @Alexhopeo’Connor: Прошло много времени с тех пор, как я работал с приложением WPF, но я использовал аналогичные решения в прошлом. Т.Е. Создайте ICommand.Execute метод async void ; Я считаю это приемлемым, поскольку ICommand.Execute логически является обработчиком событий.

5. @NurielZrubavely: если в предложении catch есть регистрация, оно должно выполняться при исключении. Однако, если вы выполняете «запуск и забываете» на ASP.NET , то любой async void метод может не завершиться.

Ответ №2:

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

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

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

Ответ №3:

Да, обычно асинхронная пустота обработчиков событий является единственным случаем. Если вы хотите узнать больше об этом, вы можете посмотреть отличное видео здесь, на канале 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".

вот ссылка

Комментарии:

1. » Обработчики событий верхнего уровня » — важный намек. При использовании обработчика событий async void в обработчике событий более низкого уровня это может вызвать огромные проблемы с не перехваченными исключениями.

2. Спасибо за ссылку на видео, очень полезно

Ответ №4:

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