Operador await – aguardar de forma assíncrona a conclusão da tarefa

O operador await suspende a avaliação do método async delimitador enquanto a operação assíncrona representada por seu operando não é concluída. Quando a operação assíncrona for concluída, o operador await retornará o resultado da operação, se houver. Quando o operador await é aplicado ao operando que representa uma operação já concluída, ele retorna o resultado da operação imediatamente sem a suspensão do método delimitador. O operador await não bloqueia o thread que avalia o método assíncrono. Quando o operador await suspende o método assíncrono delimitador, o controle é retornado ao chamador do método.

No exemplo a seguir, o método HttpClient.GetByteArrayAsync retorna a instância Task<byte[]>, que representa uma operação assíncrona que produz uma matriz de bytes quando é concluída. O operador await suspende o método DownloadDocsMainPageAsync até que a operação seja concluída. Quando DownloadDocsMainPageAsync é suspenso, o controle é retornado ao método Main, que é o chamador de DownloadDocsMainPageAsync. O método Main é executado até precisar do resultado da operação assíncrona executada pelo método DownloadDocsMainPageAsync. Quando GetByteArrayAsync obtém todos os bytes, o restante do método DownloadDocsMainPageAsync é avaliado. Depois disso, o restante do método Main é avaliado.

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.

O operando de uma expressão await deve fornecer uma notificação quando uma tarefa for concluída. Em geral, um delegado é invocado quando a tarefa é concluída com êxito ou sem êxito. A seção await da especificação de linguagem C# fornece os detalhes sobre como essas notificações são implementadas.

O exemplo anterior usa o método assíncronoMain. Para obter mais informações, confira a seção Operador await no método Main.

Observação

Para obter uma introdução à programação assíncrona, confira Programação assíncrona com async e await. A programação assíncrona com async e await segue o padrão assíncrono baseado em tarefas.

Use o operador await somente em um método, uma expressão lambda ou um método anônimo que seja modificado pela palavra-chave async. Em um método assíncrono, não é possível usar o operador await no corpo de uma função síncrona, dentro do bloco de uma instrução lock e em um contexto desprotegido.

O operando await do operador geralmente é de um dos seguintes tipos .NET: Task, Task<TResult>, ValueTask ou ValueTask<TResult>. No entanto, qualquer expressão aguardável pode ser o operando do operador await. Para obter mais informações, confira a seção Expressões aguardáveis da Especificação da linguagem C#.

O tipo de expressão await t é TResult se o tipo de expressão t é Task<TResult> ou ValueTask<TResult>. Se o tipo de t é Task ou ValueTask, o tipo de await t é void. Em ambos os casos, se t gera uma exceção, await t gera a exceção novamente.

Fluxos assíncronos e descartáveis

Você usa a instrução await foreach para consumir um fluxo assíncrono de dados. Para obter mais informações, consulte a seção sobre a instrução foreach do artigo Instruções de iteração.

Você usa a instrução await using para trabalhar com um objeto assíncrono descartável, ou seja, um objeto de um tipo que implementa uma interface IAsyncDisposable. Para obter mais informações, consulte a seção Usar descartáveis assíncronos do artigo Implementar um método DisposeAsync.

Operador await no método Main

O método Main, que é o ponto de entrada do aplicativo, pode retornar Task ou Task<int>, permitindo que ele seja assíncrono, de modo que você possa usar o operador await no corpo. Em versões anteriores do C#, para garantir que o método Main aguarde a conclusão de uma operação assíncrona, você pode recuperar o valor da propriedade Task<TResult>.Result da instância Task<TResult> retornada pelo método assíncrono correspondente. Para operações assíncronas que não produzem um valor, você pode chamar o método Task.Wait. Para saber mais sobre como selecionar a versão da linguagem, consulte Controle de versão da linguagem C#.

Especificação da linguagem C#

Para obter mais informações, confira a seção Expressões await da Especificação da linguagem C#.

Confira também