Operador await: espera asincrónicamente para que se complete una tarea

El operador await suspende la evaluación del método async envolvente hasta que se completa la operación asincrónica representada por su operando. Cuando se completa la operación asincrónica, el operador await devuelve el resultado de la operación, si existe. Cuando el operador await se aplica al operando que representa una operación ya completada, devuelve el resultado de la operación inmediatamente sin suspender el método envolvente. El operador await no bloquea el subproceso que evalúa el método async. Cuando el operador await suspende el método async envolvente, el control vuelve al autor de la llamada del método.

En el ejemplo siguiente, el método HttpClient.GetByteArrayAsync devuelve la instancia Task<byte[]>, que representa una operación asincrónica que genera una matriz de bytes cuando se completa. Hasta que se complete la operación, el operador await suspende el método DownloadDocsMainPageAsync. Cuando se suspende DownloadDocsMainPageAsync, se devuelve el control Main al método, que es el autor de la llamada a DownloadDocsMainPageAsync. El método Main se ejecuta hasta que necesita el resultado de la operación asincrónica realizada por el método DownloadDocsMainPageAsync. Cuando GetByteArrayAsync obtiene todos los bytes, se evalúa el resto del método DownloadDocsMainPageAsync. Después, se evalúa el resto del método 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.

El operando de una expresión await debe proporcionar notificaciones cuando se complete una tarea. En general, se invoca un delegado cuando se completa la tarea, ya sea correctamente o sin éxito. La sección await de la especificación del lenguaje C# proporciona los detalles sobre cómo se implementan estas notificaciones.

En el ejemplo anterior se usa el método Main asincrónico. Para obtener más información, vea la sección Operador await en el método Main.

Nota:

Para obtener una introducción a la programación asincrónica, vea Programación asincrónica con async y await. La programación asincrónica con async y await sigue el modelo asincrónico basado en tareas.

El operador await se puede usar solamente en un método, una expresión lambda o un método anónimo modificado por la palabra clave async. Dentro de un método async, no se puede usar el operador await en el cuerpo de una función sincrónica, dentro del bloque de una instrucción lock y en un contexto no seguro.

El operando del operador await suele ser de uno de los siguientes tipos de .NET: Task, Task<TResult>, ValueTask o ValueTask<TResult>. Aunque cualquier expresión con await puede ser el operando del operador await. Para obtener más información, vea la sección Expresiones con await de la especificación del lenguaje C#.

El tipo de expresión await t es TResult si el tipo de expresión t es Task<TResult> o ValueTask<TResult>. Si el tipo de t es Task o ValueTask, el tipo de await t es void. En ambos casos, si t produce una excepción, await t vuelve a producir la excepción.

Flujos asincrónicos y descartables

Se usa la instrucción await foreach para consumir un flujo de datos asincrónico. Para obtener más información, consulte la sección instrucciones foreach del artículo Instrucciones de iteración.

Se usa la instrucción await using para trabajar con un objeto descartable de forma asincrónica, es decir, un objeto de un tipo que implementa una interfaz IAsyncDisposable. Para obtener más información, vea la sección Uso de la eliminación asincrónica del artículo Implementación de un método DisposeAsync.

Operador await en el método Main

El método Main, que es el punto de entrada de la aplicación, puede devolver Task o Task<int>, lo que le permite ser asincrónico para poder usar el operador await en su cuerpo. En versiones anteriores de C#, para tener la certeza de que el método Main espera a que finalice una operación asincrónica, puede recuperar el valor de la propiedad Task<TResult>.Result de la instancia Task<TResult> devuelta por el método async correspondiente. Para las operaciones asincrónicas que no generan un valor, puede llamar al método Task.Wait. Para obtener información sobre cómo seleccionar la versión del lenguaje, vea Control de versiones del lenguaje C#.

Especificación del lenguaje C#

Para obtener más información, vea la sección Expresiones await de la especificación del lenguaje C#.

Consulte también