Operatore await: attende in modo asincrono il completamento di un'attività

L'operatore await sospende la valutazione del metodo async contenitore fino al completamento dell'operazione asincrona rappresentata dal rispettivo operando. Quando l'operazione asincrona viene completata, l'operatore await restituisce il risultato dell'operazione, se disponibile. Quando l'operatore await viene applicato all'operando che rappresenta un'operazione già completata, restituisce il risultato dell'operazione immediatamente, senza sospensione del metodo contenitore. L'operatore await non blocca il thread che valuta il metodo async. Quando l'operatore await sospende il metodo asicrono contenitore, il controllo torna al chiamante del metodo.

Nell'esempio seguente il metodo HttpClient.GetByteArrayAsync restituisce l'istanza Task<byte[]>, che rappresenta un'operazione asincrona che produce una matrice di byte quando viene completata. Fino al completamento dell'operazione, l'operatore await sospende il metodo DownloadDocsMainPageAsync. Quando DownloadDocsMainPageAsync viene sospeso, il controllo viene restituito al metodo Main, che è il chiamante di DownloadDocsMainPageAsync. Il metodo Main viene eseguito fino a quando non è necessario il risultato dell'operazione asincrona eseguita dal metodo DownloadDocsMainPageAsync. Quando GetByteArrayAsync ottiene tutti i byte, viene valutato il resto del metodo DownloadDocsMainPageAsync. Successivamente, viene valutato il resto del metodo Main.

public class AwaitOperator
{
    public static async Task Main()
    {
        Task<int> downloading = DownloadDocsMainPageAsync();
        Console.WriteLine($"{nameof(Main)}: Launched downloading.");

        int bytesLoaded = await downloading;
        Console.WriteLine($"{nameof(Main)}: Downloaded {bytesLoaded} bytes.");
    }

    private static async Task<int> DownloadDocsMainPageAsync()
    {
        Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: About to start downloading.");

        var client = new HttpClient();
        byte[] content = await client.GetByteArrayAsync("https://learn.microsoft.com/en-us/");

        Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: Finished downloading.");
        return content.Length;
    }
}
// Output similar to:
// DownloadDocsMainPageAsync: About to start downloading.
// Main: Launched downloading.
// DownloadDocsMainPageAsync: Finished downloading.
// Main: Downloaded 27700 bytes.

L'operando di un'espressione await deve fornire una notifica al completamento di un'attività. In generale, viene richiamato un delegato quando l'attività viene completata, con esito positivo o negativo. La sezione await della specifica del linguaggio C# fornisce informazioni dettagliate su come vengono implementate queste notifiche.

Nell'esempio precedente viene utilizzato il metodo asincrono Main. Per altre informazioni, vedere la sezione Operatore await nel metodo Main.

Nota

Per un'introduzione alla programmazione asincrona, vedere Programmazione asincrona con async e await. La programmazione asincrona con async e await segue il modello asincrono basato su attività.

È possibile usare l'operatore await solo in un metodo, in un'espressione lambda o in un metodo anonimo modificato dalla parola chiave async. All'interno di un metodo asincrono, non è possibile usare l'operatore await nel corpo di una funzione sincrona, all'interno del blocco di un'istruzione lock e in un contesto unsafe.

L'operando dell'operatore await è in genere di uno dei tipi .NET seguenti: Task, Task<TResult>, ValueTask o ValueTask<TResult>. Qualsiasi espressione awaitable, tuttavia, può essere l'operando dell'operatore await. Per altre informazioni, vedere la sezione Espressioni awaitable in Specifica del linguaggio C#.

Il tipo di espressione await t è TResult se il tipo di espressione t è Task<TResult> o ValueTask<TResult>. Se il tipo di t è Task o ValueTask, il tipo di await t è void. In entrambi i casi, se t genera un'eccezione, await t genera nuovamente l'eccezione.

Flussi asincroni ed elementi eliminabili

Usare l'istruzione await foreach per utilizzare un flusso asincrono di dati. Per altre informazioni, vedere la sezione relativa all'istruzione foreach dell'articolo Istruzioni di iterazione.

Usare l'istruzione await using per utilizzare un oggetto eliminabile in modo asincrono, ovvero un oggetto di un tipo che implementa un'interfaccia IAsyncDisposable. Per altre informazioni, vedere la sezione Uso di un elemento asincrono eliminabile nell'articolo Implementare un metodo DisposeAsync.

Operatore await nel metodo Main

Il metodo Main, che è il punto di ingresso dell'applicazione, può restituire Task o Task<int>, consentendo che sia asincrono, in modo da poter usare l'operatore await nel corpo. Nelle versioni di C# precedenti, per garantire che il metodo Main attenda il completamento di un'operazione asincrona, è possibile recuperare il valore della proprietà Task<TResult>.Result dell'istanza di Task<TResult> restituita dal metodo asincrono corrispondente. Per le operazioni asincrone che non producono un valore, è possibile chiamare il metodo Task.Wait. Per informazioni su come selezionare la versione del linguaggio, vedere Controllo delle versioni del linguaggio C#.

Specifiche del linguaggio C#

Per altre informazioni, vedere la sezione Espressioni await in Specifica del linguaggio C#.

Vedi anche