L'uso del suffisso "Async" nel nome di un metodo dipende dall'utilizzo del modificatore "async"?


106

Qual è la convenzione per aggiungere il suffisso ai nomi dei metodi con "Async"?

Il suffisso "Async" deve essere aggiunto solo a un metodo dichiarato con il asyncmodificatore?

public async Task<bool> ConnectAsync()

O è sufficiente che il metodo ritorni Task<T>o Task?

public Task<bool> ConnectAsync()

4
Per la parte relativa ai nomi, il documento TAP dice: I metodi asincroni in TAP includono il suffisso Async dopo il nome dell'operazione; ad esempio, GetAsync per un'operazione get. Se stai aggiungendo un metodo TAP a una classe che contiene già il nome del metodo con il suffisso Async, usa invece il suffisso TaskAsync. Ad esempio, se la classe ha già un metodo GetAsync, usa il nome GetTaskAsync.
James Manning,

4
ok, immagino di essere stato confuso dal titolo della domanda "Convenzione di denominazione per metodi asincroni"
James Manning

1
Questa è una domanda mal costruita. Persone che litigano, risposte ambigue.
Luke Puplett

4
Perché molte persone l'hanno frainteso e stanno discutendo sulla reale cosa che viene posta, chiedendosi se sia una domanda in due parti, ecc. La prova che è confusa è che le persone sono confuse.
Luke Puplett

2
@DavidRR Ancora oggi non capisco la quantità di confusione che questa domanda ha apparentemente causato. Se le tue modifiche portano un po 'di ordine nella confusione in modo tale che ti ha aiutato e forse può aiutare gli altri, allora accolgo con favore le tue modifiche perché hai ottenuto qualcosa che non potevo nella formulazione originale. La domanda ora è così vecchia che riesco a malapena a ricordare la mia mentalità quando l'ho fatta qui e quindi l'intento originale è meno importante. La risposta di Luke riflette che non tutti erano confusi. L'ho trovato immensamente utile.
kasperhj

Risposte:


127

Penso che la verità sia ambigua anche dalla documentazione di Microsoft:

In Visual Studio 2012 e .NET Framework 4.5, qualsiasi metodo attribuito con la asyncparola chiave ( Asyncin Visual Basic) è considerato un metodo asincrono ei compilatori C # e Visual Basic eseguono le trasformazioni necessarie per implementare il metodo in modo asincrono utilizzando TAP. Un metodo asincrono dovrebbe restituire a Tasko un Task<TResult>oggetto.

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

Non è già così. Qualsiasi metodo con asyncè asincrono e quindi sta dicendo che dovrebbe restituire un Tasko Task<T>- che non è corretto per i metodi nella parte superiore di uno stack di chiamate, Button_Click per esempio, o async void.

Certo, devi considerare qual è il punto della convenzione?

Si potrebbe dire che la Asyncconvenzione del suffisso è di comunicare all'utente API che il metodo è in attesa. Affinché un metodo sia attendibile, deve restituire Taskun valore void o Task<T>un metodo di restituzione del valore, il che significa che solo quest'ultimo può essere suffisso con Async.

Oppure potresti dire che la Asyncconvenzione del suffisso è di comunicare che il metodo può tornare immediatamente, abbandonando il thread corrente per eseguire altri lavori e potenzialmente causando gare.

Questa citazione di Microsoft doc dice:

Per convenzione, aggiungi "Async" ai nomi dei metodi che hanno un modificatore Async o async.

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

Il che non menziona nemmeno che i tuoi metodi asincroni che restituiscono Tasknecessitano del Asyncsuffisso, cosa che penso siamo tutti d'accordo che lo facciano.


Quindi la risposta a questa domanda potrebbe essere: entrambe. In entrambi i casi, è necessario aggiungere Asyncai metodi con la asyncparola chiave e che restituiscono Tasko Task<T>.


Chiederò a Stephen Toub di chiarire la situazione.

Aggiornare

Così ho fatto. Ed ecco cosa ha scritto il nostro brav'uomo:

Se un metodo pubblico restituisce attività ed è di natura asincrona (al contrario di un metodo noto per essere eseguito sempre in modo sincrono fino al completamento, ma restituisce comunque un'attività per qualche motivo), dovrebbe avere un suffisso "Async". Questa è la linea guida. L'obiettivo principale qui con la denominazione è rendere molto ovvio a un consumatore della funzionalità che il metodo invocato probabilmente non completerà tutto il suo lavoro in modo sincrono; ovviamente aiuta anche nel caso in cui la funzionalità sia esposta con metodi sia sincroni che asincroni in modo tale che sia necessaria una differenza di nome per distinguerli. Il modo in cui il metodo raggiunge la sua implementazione asincrona è irrilevante per la denominazione: se async / await viene utilizzato per ottenere l'aiuto del compilatore o se i tipi ei metodi da System.Threading.Tasks vengono utilizzati direttamente (ad es. g. TaskCompletionSource) non ha molta importanza, in quanto ciò non influisce sulla firma del metodo per quanto riguarda un consumatore del metodo.

Naturalmente, ci sono sempre eccezioni a una linea guida. Il più degno di nota nel caso della denominazione sarebbero i casi in cui la ragion d'essere di un intero tipo è di fornire funzionalità focalizzate sull'asincronia, nel qual caso avere Async su ogni metodo sarebbe eccessivo, ad esempio i metodi su Task stesso che producono altri Task .

Per quanto riguarda i metodi asincroni che restituiscono il vuoto, non è desiderabile averli nell'area di superficie pubblica, poiché il chiamante non ha un buon modo per sapere quando il lavoro asincrono è stato completato. Se devi esporre pubblicamente un metodo asincrono che restituisce un valore nullo, probabilmente vorrai avere un nome che comunichi che è stato avviato il lavoro asincrono e potresti usare il suffisso "Async" qui se ha senso. Dato quanto raro dovrebbe essere questo caso, direi che è davvero un tipo di decisione caso per caso.

Spero che questo aiuti, Steve

La breve guida della frase di apertura di Stephen è abbastanza chiara. Esclude async voidperché è insolito voler creare un'API pubblica con un tale design poiché il modo corretto per implementare un vuoto asincrono è restituire Taskun'istanza semplice e lasciare che il compilatore faccia la sua magia. Tuttavia, se si desidera un public async void, Asyncè consigliabile aggiungerlo . Altri async voidmetodi top-of-stack come i gestori di eventi di solito non sono pubblici e non sono importanti / qualificati.

Per me, mi dice che se mi trovo a chiedermi se aggiungere Asyncun suffisso async void, probabilmente dovrei trasformarlo in un in async Taskmodo che i chiamanti possano aspettarlo, quindi aggiungere Async.


20
Beh, è ​​un peccato che non abbiamo controlli in fase di compilazione per le chiamate ai metodi .. oh aspetta. Se nomino il metodo Get o GetAsync e non uso await dal lato chiamante, la compilazione non verrà compilata. Quindi questa convenzione è SILLY e va davvero contro molte linee guida di stile Microsoft, come evitare cose come PersonStringo PriceDecimalcosì perché usare GetAsync: i consumatori di API di API asincrone non devono preoccuparsi di questo poiché la richiesta ritorna sempre dopo che tutte le attività sono state completate comunque. È sciocco e mi dà davvero fastidio. Ma è solo un'altra convenzione che nessuno sa davvero perché è lì.
Piotr Kula

2
@ppumkin: come ha sottolineato Stephen, un metodo può essere facilmente di natura asincrona senza utilizzare async / await, quindi il chiamante non ha alcuna indicazione oltre al nome se la funzionalità è asincrona o meno.
Hannobo

6
@ppumkin: L'impossibilità di attendere un metodo asincrono, per impostazione predefinita, si traduce in un avviso in fase di compilazione; non un errore di compilazione.
Dustin Cleveland

7
Trovo sciocca questa convenzione. Esistono tre indicazioni automatiche che un metodo è asincrono: 1. Il tipo restituito è Task. 2. Il completamento del codice presenta un suggerimento in attesa 3. L'IDE ti avviserà sottolineando in verde e presentando un avviso del compilatore. Quindi sono totalmente d'accordo con @ppumkin. Il suffisso Async è sciocco come se avessi scritto una proprietà in questo modo: public Lazy <Customer> CustomerLazy. Chi lo farebbe! ??
Marco

2
@Marco Ho sollevato questa idea su GitHub, pensavo fosse il posto migliore, ma non ho l'impegno che pensavo di ottenere: github.com/dotnet/core/issues/1464
Luke Puplett

68

Realizzo molti servizi API e altre applicazioni che chiamano altri sistemi in cui la maggior parte del mio codice viene eseguito in modo asincrono.

La mia regola pratica che sto seguendo è:

Se sono presenti sia un metodo non asincrono che asincrono che restituiscono la stessa cosa, aggiungo il suffisso asincrono con Async. Altrimenti no.

Esempi:

Un solo metodo:

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

Stesso metodo con due firme:

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

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

Questo ha senso poiché sono gli stessi dati che vengono restituiti, ma l'unica cosa che differisce è il modo di restituire i dati , non i dati stessi.

Penso anche che queste convenzioni di denominazione esistano a causa della necessità di introdurre metodi asincroni e mantenere comunque la compatibilità con le versioni precedenti.

Sostengo che il nuovo codice non dovrebbe usare il suffisso Async. È altrettanto ovvio del tipo restituito di String o Int come menzionato prima in questo thread.


8
Sono d'accordo, soprattutto sul fatto che di solito devi andare "asincrono fino in fondo", nel qual caso il suffisso è ridondante - qual è il punto di aggiungerlo al 90% del codice;)
Bartosz

3
questa è la soluzione migliore. Senza accorgermene, ho fatto lo stesso con le mie API.
Marco

2
Questo è molto meglio del suffisso con "Async" tutti i metodi di applicazione asincrona
Mariusz Jamro,

Il problema con questa tecnica è che se in seguito crei una versione non asincrona, non puoi usare il nome "GetUser ()" altrimenti preferito.
David

3
Questa è la strada pragmatica da percorrere. Aggiungere Async a ogni metodo che ha il modificatore async è solo ungherese Notation 2019. @David se si finisce per aggiungere una versione non asincrona in un secondo momento, rinominare i metodi e seguire la convenzione di denominazione o semplicemente non farlo.
Skrymsli

25

Qual è la convenzione per aggiungere come suffisso "Async" ai nomi dei metodi.

Il TAP (Task-based Asynchronous Pattern) impone che i metodi restituiscano sempre un Task<T>(o Task) e vengano denominati con un suffisso Async ; questo è separato dall'uso di async. Entrambi Task<bool> Connect()e verranno compilati ed eseguiti correttamente, ma non seguirai la convenzione di denominazione TAP.asyncTask<bool> Connect()

Il metodo dovrebbe contenere il asyncmodificatore o è sufficiente che restituisca semplicemente Task?

Se il corpo del metodo (indipendentemente dal tipo o dal nome restituito) include await, è necessario utilizzare async; e il compilatore ti dirà "L'operatore 'await' può essere utilizzato solo all'interno di un metodo asincrono ...". Restituire Task<T>o Tasknon è "sufficiente" per evitare di utilizzare async. Vedere async (riferimenti per C #) per i dettagli.

Cioè quali di queste firme sono corrette:

Entrambi e seguire correttamente le convenzioni TAP. È sempre possibile utilizzare la parola chiave, ma verrà visualizzato un avviso del compilatore "Questo metodo asincrono non dispone di operatori 'await' e verrà eseguito in modo sincrono. ..." se il corpo non utilizza .asyncTask<bool> ConnectAsync()Task<bool> ConnectAsync()asyncawait


1
Si riferisce al fatto che tu aggiunga o meno "Async" al nome del metodo, non se usi la asyncparola chiave.
Servy

1
@Servy se si utilizza o meno la parola chiave asyncè la seconda parte della domanda.
Corak

2
@Servy È una domanda in due parti. La prima parte, come hai detto, è se aggiungere o meno "Async" al nome del metodo. La seconda parte è se usare o meno il asyncmodificatore. Vedi anche esempi di OP, public async Task<bool> ConnectAsync()(con asyncmodificatore) vs public Task<bool> ConnectAsync()(senza asyncmodificatore). Il nome del metodo stesso ha il suffisso "Async" in entrambi i casi.
Corak

2
E ' non è una domanda in due parti. La domanda è: "Async" dovrebbe essere aggiunto ai nomi dei metodi dei metodi che restituiscono Tasko ai metodi che hanno async Task.
kasperhj

3
@lejon: dovresti migliorare la domanda; il "vs." frammenti di codice rendono chiaro che la domanda (nella sua interezza) riguarda l'asincronia poiché questa è l'unica differenza.
Ðаn

11

o è sufficiente che restituisca solo Task?

Quello. La asyncparola chiave non è il vero problema qui. Se si implementa l'asincronia senza utilizzare la asyncparola chiave il metodo è ancora "Asincrono", in senso generale.


7

Poiché Taske Task<T>sono entrambi i tipi awaitable, rappresentano alcune operazioni asincrone. O almeno dovrebbero rappresentare.

È necessario aggiungere un suffisso Asynca un metodo che, in alcuni casi (non necessariamente tutti), non restituisce un valore ma restituisce piuttosto un wrapper attorno a un'operazione in corso. Quel wrapper è solitamente un Task, ma su Windows RT può esserlo IAsyncInfo. Segui il tuo istinto e ricorda che se un utente del tuo codice vede la Asyncfunzione, saprà che l'invocazione di quel metodo è disaccoppiata dal risultato di quel metodo e che deve agire di conseguenza.

Nota che ci sono metodi come Task.Delaye Task.WhenAllche restituiscono Taske tuttavia non hanno il Asyncsuffisso.

Nota anche che ci sono async voidmetodi che rappresentano il fuoco e dimentica il metodo asincrono e dovresti essere meglio consapevole che il metodo è costruito in questo modo.


6

Direi che dovrebbe usare il suffisso Async se restituisce un'attività indipendentemente dal fatto che il metodo sia dichiarato con il asyncmodificatore o meno.

Il motivo è che il nome è dichiarato nell'interfaccia. L'interfaccia dichiara il tipo di ritorno che è un file Task. Poi ci sono due implementazioni di quell'interfaccia, un'implementazione la implementa usando il asyncmodificatore, l'altra no.

public interface IFoo
{
    Task FooAsync();
}

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

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

È così vero. Usiamo sempre interfacce, ovunque, e le interfacce non possono essere dichiarate asincrone. Quindi le guide ufficiali sull'uso del suffisso Async mi sembrano completamente senza senso. Penso che la parola chiave async sia solo un dettaglio di implementazione, parte degli interni del metodo e non dovrebbe influenzare il suo nome o qualsiasi altra cosa esterna.
Al Kepp,

5

Nella programmazione asincrona con async and await (C #) , Microsoft offre le seguenti indicazioni:

Convenzione sulla denominazione

Per convenzione, aggiungi "Async" ai nomi dei metodi che hanno un modificatore async .

È possibile ignorare la convenzione in cui un evento, una classe base o un contratto di interfaccia suggerisce un nome diverso. Ad esempio, non rinominare i gestori di eventi comuni, come Button1_Click.

Trovo questa guida incompleta e insoddisfacente. Ciò significa che in assenza del asyncmodificatore, questo metodo dovrebbe essere nominato al Connectposto di ConnectAsync?

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

Non credo proprio. Come indicato nella risposta concisa di @Servy e nella risposta più dettagliata di @Luke Puplett , credo che sia appropriato e in effetti previsto che questo metodo debba essere nominato ConnectAsync(perché restituisce un awaitable). A ulteriore supporto di ciò, @John Skeet in questa risposta a un'altra domanda viene aggiunto Asyncal nome del metodo indipendentemente dalla presenza delasync modificatore.

Infine, su un'altra domanda , considera questo commento di @Damien_The_Unbeliever :

async/awaitsono dettagli di implementazione dei tuoi metodi. Non importa neanche un punto se il tuo metodo è dichiaratoasync Task Method() o solo Task Method(), per quanto riguarda i chiamanti . (In effetti, sei libero di cambiare tra questi due in un secondo momento senza che sia considerato un cambiamento di rottura.)

Da ciò, deduco che è la natura asincrona del metodo che determina come dovrebbe essere chiamato. L'utente del metodo non saprà nemmeno se il asyncmodificatore viene utilizzato nella sua implementazione (senza il codice sorgente C # o CIL).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.