Dois-je éviter les gestionnaires d'événements «async void»?

119

Je sais qu'il est généralement considéré comme une mauvaise idée d'utiliser des méthodes d'incendie et d'oubli async voidpour démarrer des tâches, car il n'y a pas de trace de la tâche en attente et il est difficile de gérer les exceptions qui pourraient être lancées dans une telle méthode.

Dois-je généralement éviter les async voidgestionnaires d'événements? Par exemple,

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

Je peux le réécrire comme ceci:

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
        // ...
} 

Quelles sont les roches sous-marines pour les gestionnaires d'événements asynchrones, en plus d'une éventuelle ré-entrée?

éviter
la source
Vous devriez mais vous ne pouvez pas. En plus de cela, tous les soins que vous devez prendre lors de l'utilisation d'async void sont déjà requis par les gestionnaires d'événements de l'interface utilisateur.
Paulo Morgado
Et la réentrance se produit en raison d'opérations asynchrones déclenchées par le gestionnaire d'événements et non par l'utilisation de async-await par lui-même.
Paulo Morgado

Réponses:

153

La règle est d'éviter async void sauf lorsqu'il est utilisé dans un gestionnaire d'événements, donc l'utilisation async voiddans un gestionnaire d'événements est OK.

Cela dit, pour des raisons de tests unitaires , j'aime souvent exclure la logique de toutes les async voidméthodes. Par exemple,

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);
}
Stephen Cleary
la source
Je suis curieux ... y a-t-il une raison pour laquelle vous ne changez pas simplement Form_Loadl'accès à public? Il semble que le code serait moins détaillé de cette façon.
InteXX
Oups, peu importe ... VBer essaie de lire C # ici ... Je viens de remarquer le type de retour de OnFormLoadAsync. Je vois maintenant que cela constitue un truc pratique. Merci.
InteXX
Cela dit, pourriez-vous jeter un oeil et donner un avis ici . Merci!
InteXX
2
@ AlexHopeO'Connor: Le Handleddrapeau doit être défini de manière synchrone; il n'est pas possible d'utiliser asyncpour décider si l'événement est géré ou non.
Stephen Cleary
2
@ AlexHopeO'Connor: Cela fait un moment que je n'ai pas travaillé avec une application WPF, mais j'ai utilisé des solutions similaires dans le passé. Ie, faites la ICommand.Executeméthode async void; Je considère cela comme acceptable car il ICommand.Executes'agit logiquement d' un gestionnaire d'événements.
Stephen Cleary
50

Dois-je généralement éviter les gestionnaires d'événements async void?

En général, les gestionnaires d'événements sont le seul cas où une méthode async void n'est pas une odeur de code potentielle.

Maintenant, si vous avez besoin de suivre la tâche pour une raison quelconque, la technique que vous décrivez est parfaitement raisonnable.

Eric Lippert
la source
6

Oui, généralement asynchrone vide de gestionnaires d'événements est le seul cas. Si vous voulez en savoir plus à ce sujet, vous pouvez regarder une superbe vidéo ici sur le canal 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".

voici le lien

Idrees Khan
la source
Les « gestionnaires d'événements de premier niveau » sont un indice important. Lorsque vous utilisez le gestionnaire d'événements async void sur un gestionnaire d'événements de niveau inférieur, cela peut causer d'énormes problèmes avec des exceptions non interceptées.
Portikus
Merci pour le lien vidéo, très utile
lsp
5

Si vous utilisez ReSharper, une extension ReCommended gratuite pourrait vous être utile. Il analyse les méthodes «async void» et met en évidence lorsqu'elles sont utilisées de manière inappropriée. L'extension peut distinguer différentes utilisations de async void et fournir des correctifs rapides appropriés décrits ici: wiki ReCommended-Extension .

Alexander Zwitbaum
la source