Чи слід уникати обробників подій "async void"?


119

Я знаю, що загалом вважається поганою ідеєю використовувати 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
        // ...
} 

Які є підводні скелі для асинхронних обробників подій, окрім можливої ​​повторної участі?


Ти повинен, але не можеш. Крім того, всі турботи, які ви повинні взяти під час використання асинхроністичної порожнечі, вже вимагають обробники подій інтерфейсу користувача.
Пауло Моргадо

А повторне ставлення відбувається через асинхронні операції, запущені обробником подій, а не через використання асинхрон-очікування самого себе.
Пауло Моргадо

Відповіді:


153

Настанова полягає в тому, щоб уникати, 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);
}

Мені цікаво ... чи є причина, чому ви не просто змінюєте Form_Loadдоступ public? Здається, що такий код буде менш дослідним.
InteXX

На жаль, VBer намагається прочитати C # тут ... Я щойно помітив тип повернення OnFormLoadAsync. Зараз я бачу, що це сприятливо вигадує. Дякую.
InteXX

Все, що сказано, ви можете подивитися і запропонувати свою думку тут . Дякую!
InteXX

2
@ AlexHopeO'Connor: Handledпрапор повинен бути встановлений синхронно; не можна використовувати asyncдля прийняття рішення про те, чи проводиться подія чи ні.
Стівен Клірі

2
@ AlexHopeO'Connor: Минув час, коли я працював із програмою WPF, але в минулому я використовував рішення, подібні до того, що було. Тобто зробити ICommand.Executeметод async void; Я вважаю це прийнятним , оскільки ICommand.Executeє логічно обробник події.
Стівен Клірі

50

Чи варто взагалі уникати асинхронних обробників недійсних подій?

Як правило, обробники подій - це один випадок, коли метод асинхронізації, який недійсний, не є потенційним запахом коду.

Тепер, якщо вам потрібно чомусь відстежувати завдання, то описана вами техніка цілком розумна.


6

Так, як правило, асинхронізація недійсних обробників подій є єдиним випадком. Якщо ви хочете дізнатися більше про це, ви можете подивитися чудове відео тут на каналі 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".

ось посилання


«Оператори подій верхнього рівня » є важливим підказом. Під час використання асинхронного обробника недійсних подій на обробці подій нижчого рівня це може призвести до величезних проблем із не зловленими винятками.
Портикус

Дякую за відео посилання, дуже корисне
lsp

5

Якщо ви використовуєте ReSharper, вам може бути корисно безкоштовне рекомендоване розширення . Він аналізує методи "асинхронізовані порожнечі" та виділяє при неправильному використанні. Розширення може розрізняти різні способи використання асинхроністих пустот і надавати відповідні швидкі виправлення, описані тут: Вікі для перегляду рекомендацій .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.