L'utilisation du suffixe «Async» dans un nom de méthode dépend-elle de l'utilisation ou non du modificateur «async»?

107

Quelle est la convention pour suffixer les noms de méthodes avec "Async"?

Le suffixe "Async" doit-il être ajouté uniquement à une méthode déclarée avec le asyncmodificateur?

public async Task<bool> ConnectAsync()

Ou est-ce suffisant que la méthode retourne simplement Task<T>ou Task?

public Task<bool> ConnectAsync()
Kasperhj
la source
4
Pour la partie nommage, le document TAP dit: Les méthodes asynchrones dans TAP incluent le suffixe Async après le nom de l'opération; par exemple, GetAsync pour une opération get. Si vous ajoutez une méthode TAP à une classe qui contient déjà ce nom de méthode avec le suffixe Async, utilisez plutôt le suffixe TaskAsync. Par exemple, si la classe a déjà une méthode GetAsync, utilisez le nom GetTaskAsync.
James Manning
4
ok, je suppose que j'ai été confus par le titre de la question "Convention de dénomination pour les méthodes asynchrones"
James Manning
1
C'est une question mal construite. Les gens se chamaillent, réponses équivoques.
Luke Puplett
4
Parce que beaucoup de gens l'ont mal compris et se disputent quant à la chose réelle posée, se demandant si c'est une question en deux parties, etc. La preuve que c'est déroutant est que les gens sont confus.
Luke Puplett
2
@DavidRR À ce jour, je ne comprends toujours pas la confusion que cette question a apparemment causée. Si vos modifications apportent un peu d'ordre dans la confusion de telle sorte que cela vous a aidé et peut-être peut-être aider les autres, alors je me réjouis de vos modifications car vous avez réalisé quelque chose que je ne pouvais pas dans la formulation originale. La question est maintenant si ancienne que je peux à peine me souvenir de mon état d'esprit lorsque je l'ai posée ici et l'intention initiale est donc moins importante. La réponse de Luke reflète que tous n'étaient pas confus. Je l'ai trouvé extrêmement utile.
kasperhj

Réponses:

128

Je pense que la vérité est ambiguë même à partir de la documentation Microsoft:

Dans Visual Studio 2012 et .NET Framework 4.5, toute méthode attribuée avec le asyncmot clé ( Asyncdans Visual Basic) est considérée comme une méthode asynchrone, et les compilateurs C # et Visual Basic effectuent les transformations nécessaires pour implémenter la méthode de manière asynchrone à l'aide de TAP. Une méthode asynchrone doit renvoyer Taskun Task<TResult>objet ou un objet.

http://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx

Ce n'est pas déjà vrai. Toute méthode avec asyncest asynchrone et elle dit qu'elle doit retourner soit a Taskou Task<T>- ce qui n'est pas correct pour les méthodes en haut d'une pile d'appels, Button_Click par exemple, ou async void.

Bien sûr, vous devez vous demander quel est l’intérêt de la convention?

Vous pourriez dire que la Asyncconvention de suffixe est de communiquer à l'utilisateur de l'API que la méthode est attendue. Pour qu'une méthode soit attendue, elle doit retourner Taskpour un void, ou Task<T>pour une méthode de retour de valeur, ce qui signifie que seule cette dernière peut être suffixée Async.

Ou vous pourriez dire que la Asyncconvention de suffixe est de communiquer que la méthode peut retourner immédiatement, abandonnant le thread actuel pour effectuer un autre travail et provoquant potentiellement des courses.

Cette citation de Microsoft doc dit:

Par convention, vous ajoutez «Async» aux noms des méthodes qui ont un modificateur Async ou async.

http://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_NamingConvention

Ce qui ne mentionne même pas que vos propres méthodes asynchrones retournant ont Taskbesoin du Asyncsuffixe, ce que je pense que nous sommes tous d'accord pour dire qu'ils le font.


La réponse à cette question pourrait donc être: les deux. Dans les deux cas, vous devez ajouter Asyncaux méthodes avec un asyncmot-clé et qui renvoie Taskou Task<T>.


Je vais demander à Stephen Toub de clarifier la situation.

Mettre à jour

Alors je l'ai fait. Et voici ce que notre brave homme a écrit:

Si une méthode publique renvoie une tâche et est de nature asynchrone (par opposition à une méthode connue pour s'exécuter toujours de manière synchrone jusqu'à la fin mais qui retourne toujours une tâche pour une raison quelconque), elle doit avoir un suffixe «Async». C'est la ligne directrice. Le but principal ici avec la dénomination est de rendre très évident pour un consommateur de la fonctionnalité que la méthode appelée ne terminera probablement pas tout son travail de manière synchrone; cela aide bien sûr également dans le cas où la fonctionnalité est exposée avec des méthodes synchrones et asynchrones, de sorte que vous avez besoin d'une différence de nom pour les distinguer. La manière dont la méthode réalise son implémentation asynchrone n'a pas d'importance pour la dénomination: si async / await est utilisé pour obtenir l'aide du compilateur, ou si les types et méthodes de System.Threading.Tasks sont utilisés directement (e. g. TaskCompletionSource) n'a pas vraiment d'importance, car cela n'affecte pas la signature de la méthode en ce qui concerne le consommateur de la méthode.

Bien sûr, il y a toujours des exceptions à une directive. Le plus notable dans le cas de la dénomination serait les cas où la raison d'être d'un type entier est de fournir des fonctionnalités axées sur l'async, auquel cas avoir Async sur chaque méthode serait excessif, par exemple les méthodes sur Task elle-même qui produisent d'autres tâches. .

En ce qui concerne les méthodes asynchrones à retour de vide, il n'est pas souhaitable de les avoir dans la zone publique, car l'appelant n'a aucun bon moyen de savoir quand le travail asynchrone est terminé. Cependant, si vous devez exposer publiquement une méthode asynchrone à retour vide, vous souhaiterez probablement avoir un nom qui indique que le travail asynchrone est en cours de lancement, et vous pouvez utiliser le suffixe «Async» ici si cela a du sens. Compte tenu de la rareté de ce cas, je dirais que c'est vraiment une décision au cas par cas.

J'espère que ça aide, Steve

Les conseils succincts de la phrase d'ouverture de Stephen sont assez clairs. Cela exclut async voidcar il est inhabituel de vouloir créer une API publique avec une telle conception, car la manière correcte d'implémenter un vide asynchrone est de retourner une Taskinstance simple et de laisser le compilateur faire sa magie. Cependant, si vous voulez un public async void, alors l'ajout Asyncest conseillé. D'autres async voidméthodes de haut de gamme telles que les gestionnaires d'événements ne sont généralement pas publiques et n'ont pas d'importance / ne sont pas qualifiées.

Pour moi, cela me dit que si je me pose des questions sur le suffixe Asyncsur un async void, je devrais probablement le transformer en un async Taskpour que les appelants puissent l'attendre, puis l'ajouter Async.

Luke Puplett
la source
20
Eh bien, c'est dommage que nous n'ayons pas de contrôles de temps de compilation pour les appels de méthode ... oh attendez. Si je nomme la méthode Get ou GetAsync et ne pas utiliser await du côté appelant, la compilation ne parviendra pas à construire. Donc, cette convention est SILLY et va vraiment à l'encontre de nombreuses directives de style Microsoft, comme éviter des choses comme PersonStringou PriceDecimalalors pourquoi l'utiliser GetAsync- les consommateurs d'API d'API async n'ont pas à s'inquiéter à ce sujet car la demande revient toujours une fois toutes les tâches terminées de toute façon. C'est idiot et vraiment ennuyeux. Mais c'est juste une autre convention que personne ne sait vraiment pourquoi c'est là.
Piotr Kula
2
@ppumkin: Comme Stephen l'a souligné, une méthode peut facilement être de nature asynchrone sans utiliser async / await, ainsi l'appelant n'a aucune indication autre que le nom si la fonctionnalité s'exécute ou non de manière asynchrone.
Hannobo
6
@ppumkin: Ne pas attendre une méthode asynchrone, par défaut, entraîne un avertissement lors de la compilation; pas une erreur de construction.
Dustin Cleveland
7
Je trouve cette convention idiote. Il existe trois indications automatiques indiquant qu'une méthode est asynchrone: 1. Le type de retour est Tâche. 2. La complétion du code présente un indice attendu 3. l'EDI vous avertira en soulignant en vert et en présentant un avertissement du compilateur. Je suis donc totalement d'accord avec @ppumkin. Le suffixe Async est aussi ridicule que si vous écriviez une propriété comme celle-ci: public Lazy <Customer> CustomerLazy. Qui ferait ça! ??
Marco
2
@Marco J'ai soulevé cette idée sur GitHub, je pensais que c'était le meilleur endroit, mais je n'ai pas l'engagement avec lui, je pensais obtenir: github.com/dotnet/core/issues/1464
Luke Puplett
68

Je construis beaucoup de services API et d'autres applications qui appellent d'autres systèmes où la plupart de mon code s'exécute de manière asynchrone.

Ma propre règle de base que je suis:

S'il existe à la fois des méthodes non async et async qui renvoient la même chose, je suffixe l'async avec Async. Sinon non.

Exemples:

Une seule méthode:

public async Task<User> GetUser() { [...] }

Même méthode avec deux signatures:

public User GetUser() { [...] }

public async Task<User> GetUserAsync() { [...] }

Cela a du sens car ce sont les mêmes données qui sont renvoyées, mais la seule chose qui diffère est la manière de renvoyer les données , pas les données elles-mêmes.

Je pense également que ces conventions de dénomination existent en raison de la nécessité d'introduire des méthodes asynchrones tout en conservant la compatibilité ascendante.

Je soutiens que le nouveau code ne devrait pas utiliser le suffixe Async. C'est tout aussi évident que le type de retour String ou Int comme mentionné précédemment dans ce thread.

Jonas Stensved
la source
8
Je suis d'accord, surtout que d'habitude, vous devez aller `` asynchrone complètement '', auquel cas le suffixe est redondant - quel est l'intérêt de l'ajouter à 90% du code;)
Bartosz
3
C'est la meilleure solution. Sans m'en apercevoir, j'ai fait de même dans mes API.
Marco
2
C'est bien mieux que de suffixer avec "Async" toutes les méthodes d'application asynchrone
Mariusz Jamro
Le problème avec cette technique est que si vous créez ultérieurement une version non asynchrone, vous ne pouvez pas utiliser votre nom "GetUser ()" par ailleurs préféré.
David
3
C'est la voie pragmatique à suivre. Ajouter Async à chaque méthode qui a le modificateur async est juste la notation hongroise 2019. @David si vous finissez par ajouter une version non async plus tard, renommez les méthodes et suivez la convention de dénomination ou ne faites tout simplement pas cela.
Skrymsli
25

Quelle est la convention pour suffixer les noms de méthodes avec "Async".

Le modèle asynchrone basé sur les tâches (TAP) dicte que les méthodes doivent toujours renvoyer un Task<T>(ou Task) et être nommées avec un suffixe Async ; ceci est distinct de l'utilisation de async. Les deux Task<bool> Connect()et se compileront et fonctionneront très bien, mais vous ne suivrez pas la convention de dénomination TAP.asyncTask<bool> Connect()

La méthode devrait-elle contenir le asyncmodificateur, ou suffisamment pour qu'elle renvoie simplement Task?

Si le corps de la méthode (quel que soit le type ou le nom de retour) inclut await, vous devez utiliser async; et le compilateur vous dira "L'opérateur 'await' ne peut être utilisé que dans une méthode asynchrone. ...". Le retour Task<T>ou Taskn'est pas "suffisant" pour éviter d'utiliser async. Voir async (référence C #) pour plus de détails.

C'est à dire laquelle de ces signatures est correcte:

Les deux et respectent correctement les conventions TAP. Vous pouvez toujours utiliser le mot - clé, mais vous obtiendrez un avertissement du compilateur "Cette méthode asynchrone ne dispose pas des opérateurs 'await' et s'exécutera de manière synchrone. ..." si le corps ne l'utilise pas .asyncTask<bool> ConnectAsync()Task<bool> ConnectAsync()asyncawait

Ðаn
la source
1
Il se réfère à savoir si vous ajoutez ou non "Async" au nom de la méthode, pas si vous utilisez le asyncmot - clé.
Servy le
1
@Servy que vous utilisiez ou non le mot async- clé est la deuxième partie de la question.
Corak
2
@Servy C'est une question en deux parties. La première partie, comme vous l'avez dit, est de savoir s'il faut ou non ajouter "Async" au nom de la méthode. La deuxième partie consiste à savoir s'il faut utiliser ou non le asyncmodificateur. Voir aussi les exemples OP, public async Task<bool> ConnectAsync()(avec asyncmodificateur) vs public Task<bool> ConnectAsync()(sans asyncmodificateur). Le nom de la méthode lui-même a le suffixe "Async" dans les deux cas.
Corak
2
Ce n'est pas une question en deux parties. La question est de savoir si "Async" doit être ajouté aux noms de méthodes des méthodes qui renvoient Taskou des méthodes qui ont async Task.
kasperhj
3
@lejon: vous devriez améliorer la question; le "vs." Les extraits de code indiquent clairement que la question (dans son intégralité) concerne l'async, car c'est la seule différence.
Ðаn
11

ou suffit-il qu'il renvoie simplement Task?

Cette. Le asyncmot clé n'est pas le vrai problème ici. Si vous implémentez l'asynchronie sans utiliser le asyncmot - clé, la méthode est toujours "Async", au sens général.

Servy
la source
7

Depuis Tasket Task<T>sont tous deux des types attendables, ils représentent certains opération asynchrone. Ou du moins, ils devraient représenter.

Vous devez ajouter un suffixe Asyncà une méthode qui, dans certains cas (pas nécessairement tous), ne renvoie pas de valeur mais renvoie plutôt un wrapper autour d'une opération en cours. Ce wrapper est généralement un Task, mais sur Windows RT, il peut l'être IAsyncInfo. Suivez votre instinct et rappelez-vous que si un utilisateur de votre code voit la Asyncfonction, il saura que l'invocation de cette méthode est découplée du résultat de cette méthode et qu'il doit agir en conséquence.

Notez qu'il existe des méthodes telles que Task.Delayet Task.WhenAllqui retournent Tasket qui n'ont pas le Asyncsuffixe.

Notez également qu'il existe des async voidméthodes qui représentent le feu et oublient la méthode asynchrone et vous devriez mieux être conscient que la méthode est construite de cette manière.

Toni Petrina
la source
6

Je dirais qu'il devrait utiliser le suffixe Async s'il renvoie une tâche, que la méthode soit déclarée avec le asyncmodificateur ou non.

La raison en est que le nom est déclaré dans l'interface. L'interface déclare le type de retour qui est un Task. Ensuite, il y a deux implémentations de cette interface, une implémentation l'implémente en utilisant le asyncmodificateur, l'autre non.

public interface IFoo
{
    Task FooAsync();
}

public class FooA : IFoo
{
    public Task FooAsync() { /* ... */ }
}

public class FooB : IFoo
{
    public async Task FooAsync() { /* ... */ }
}
Fred
la source
C'est tellement vrai. Nous utilisons toujours des interfaces, partout, et les interfaces ne peuvent pas être déclarées asynchrones. Donc, les guides officiels sur l'utilisation du suffixe Async me semblent complètement absurdes. Je pense que le mot-clé async est juste un détail d'implémentation, une partie des composants internes de la méthode, et ne devrait pas influencer son nom ou quoi que ce soit externe.
Al Kepp
5

Dans la programmation asynchrone avec async et await (C #) , Microsoft propose les conseils suivants:

Convention de dénomination

Par convention, vous ajoutez «Async» aux noms des méthodes qui ont un modificateur async .

Vous pouvez ignorer la convention selon laquelle un événement, une classe de base ou un contrat d'interface suggère un nom différent. Par exemple, vous ne devez pas renommer les gestionnaires d'événements courants, tels que Button1_Click.

Je trouve cette orientation incomplète et insatisfaisante. Cela signifie-t-il qu'en l'absence du asyncmodificateur, cette méthode devrait être nommée à la Connectplace de ConnectAsync?

public Task<bool> ConnectAsync()
{
    return ConnectAsyncInternal();
}

Je ne pense pas. Comme indiqué dans la réponse concise par @Servy et plus réponse détaillée par @Luke Puplett , je crois qu'il est approprié et bien prévu que cette méthode devrait être nommé ConnectAsync(car il renvoie un awaitable). À l'appui de cela, @John Skeet dans cette réponse à une autre question ajoute Asyncau nom de la méthode indépendamment de la présence du asyncmodificateur.

Enfin, sur une autre question , considérez ce commentaire de @Damien_The_Unbeliever :

async/awaitsont les détails de mise en œuvre de vos méthodes. Peu importe que votre méthode soit déclarée async Task Method()ou juste Task Method(), en ce qui concerne vos appelants . (En fait, vous êtes libre de changer entre ces deux à un moment ultérieur sans que cela soit considéré comme un changement radical.)

De là, j'en déduis que c'est la nature asynchrone de la méthode qui dicte comment elle doit être nommée. L'utilisateur de la méthode ne saura même pas si le asyncmodificateur est utilisé dans son implémentation (sans le code source C # ou CIL).

DavidRR
la source