Редактиране

Споделяне чрез


await operator - asynchronously await for a task to complete

The await operator suspends evaluation of the enclosing async method until the asynchronous operation represented by its operand completes. When the asynchronous operation completes, the await operator returns the result of the operation, if any. When the await operator is applied to the operand that represents an already completed operation, it returns the result of the operation immediately without suspension of the enclosing method. The await operator doesn't block the thread that evaluates the async method. When the await operator suspends the enclosing async method, the control returns to the caller of the method.

In the following example, the HttpClient.GetByteArrayAsync method returns the Task<byte[]> instance, which represents an asynchronous operation that produces a byte array when it completes. Until the operation completes, the await operator suspends the DownloadDocsMainPageAsync method. When DownloadDocsMainPageAsync gets suspended, control is returned to the Main method, which is the caller of DownloadDocsMainPageAsync. The Main method executes until it needs the result of the asynchronous operation performed by the DownloadDocsMainPageAsync method. When GetByteArrayAsync gets all the bytes, the rest of the DownloadDocsMainPageAsync method is evaluated. After that, the rest of the Main method is evaluated.

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.

The operand of an await expression must provide for notification when a task completes. In general, a delegate is invoked when the task completes, either successfully or unsuccessfully. The await section of the C# language spec provides the details on how these notifications are implemented.

The preceding example uses the async Main method. For more information, see the await operator in the Main method section.

Note

For an introduction to asynchronous programming, see Asynchronous programming with async and await. Asynchronous programming with async and await follows the task-based asynchronous pattern.

You can use the await operator only in a method, lambda expression, or anonymous method that is modified by the async keyword. Within an async method, you can't use the await operator in the body of a synchronous local function, inside the block of a lock statement, and in an unsafe context.

The operand of the await operator is usually of one of the following .NET types: Task, Task<TResult>, ValueTask, or ValueTask<TResult>. However, any awaitable expression can be the operand of the await operator. For more information, see the Awaitable expressions section of the C# language specification.

The type of expression await t is TResult if the type of expression t is Task<TResult> or ValueTask<TResult>. If the type of t is Task or ValueTask, the type of await t is void. In both cases, if t throws an exception, await t rethrows the exception.

Asynchronous streams and disposables

You use the await foreach statement to consume an asynchronous stream of data. For more information, see the foreach statement section of the Iteration statements article.

You use the await using statement to work with an asynchronously disposable object, that is, an object of a type that implements an IAsyncDisposable interface. For more information, see the Using async disposable section of the Implement a DisposeAsync method article.

await operator in the Main method

The Main method, which is the application entry point, can return Task or Task<int>, enabling it to be async so you can use the await operator in its body. In earlier C# versions, to ensure that the Main method waits for the completion of an asynchronous operation, you can retrieve the value of the Task<TResult>.Result property of the Task<TResult> instance that is returned by the corresponding async method. For asynchronous operations that don't produce a value, you can call the Task.Wait method. For information about how to select the language version, see C# language versioning.

C# language specification

For more information, see the Await expressions section of the C# language specification.

See also