web-dev-qa-db-fra.com

Est-il OK d'avoir une méthode asynchrone virtuelle sur la classe de base?

Je travaille avec du code, où j'ai 2 classes avec une logique et un code très similaires. J'ai la méthode protected async void LoadDataAsync() sur les deux classes.
Actuellement, je le refactorise et je pense à déplacer la logique partagée vers la classe de base.
Est-il OK d'avoir virtual async méthode sur la classe de base et la remplacer sur les classes dérivées?
Y a-t-il des problèmes avec cela?
Mon code ressemble à ceci:

public class Base
{
   protected virtual async void LoadDataAsync() {}
}

public class Derived : Base
{
   protected override async void LoadDataAsync()
   {
       // awaiting something
   }
}

Similaire (mais pas le même) la question a déjà été posée.

41
Samvel Siradeghyan

Réponse courte

  • Une méthode virtualpeut être marquée comme async
  • Une méthode abstractne peut pas être marquée comme async

La raison en est que async ne fait pas réellement partie de la signature de la méthode. Il indique simplement au compilateur comment gérer la compilation du corps de la méthode lui-même (et ne s'applique pas aux méthodes de substitution). Puisqu'une méthode abstraite n'a pas de corps de méthode, il n'est pas logique d'appliquer le modificateur async.

Longue réponse

Plutôt que votre signature actuelle dans la classe de base, je recommanderais ce qui suit si la classe de base fournit une implémentation par défaut de la méthode mais n'a pas besoin de faire de travail.

protected virtual Task LoadDataAsync() {
  return Task.FromResult(default(object));
}

Les principaux changements par rapport à votre implémentation sont les suivants:

  1. Modifiez la valeur de retour de void en Task (rappelez-vous que async ne fait pas réellement partie du type de retour). Contrairement au renvoi de void, lorsqu'un Task est renvoyé, le code appelant peut effectuer l'une des opérations suivantes:
    • Attendez la fin de l'opération
    • Vérifier l'état de la tâche (terminée, annulée, défectueuse)
  2. Évitez d'utiliser le modificateur async, car la méthode n'a pas besoin de await quoi que ce soit. À la place, renvoyez simplement une instance Task déjà terminée. Les méthodes qui remplacent cette méthode pourront toujours utiliser le modificateur async si elles en ont besoin.
70
Sam Harwell

Oui, ça va, mais vous devez utiliser async Task au lieu de async void. J'ai un article MSDN qui explique pourquoi .

19
Stephen Cleary