await 运算符(C# 参考)await operator (C# reference)

await 运算符暂停对封闭 async 方法的求值,直到其操作数表示的异步操作完成。The await operator suspends evaluation of the enclosing async method until the asynchronous operation represented by its operand completes. 异步操作完成后,await 运算符将返回操作的结果(如果有)。When the asynchronous operation completes, the await operator returns the result of the operation, if any. await 运算符应用到表示已完成操作的操作数时,它将立即返回操作的结果,而不会暂停封闭的方法。When the await operator is applied to the operand that represents already completed operation, it returns the result of the operation immediately without suspension of the enclosing method. await 运算符不会阻止计算异步方法的线程。The await operator doesn't block the thread that evaluates the async method. await 运算符暂停封闭的异步方法时,控件将返回到方法的调用方。When the await operator suspends the enclosing async method, the control returns to the caller of the method.

在下面的示例中,HttpClient.GetByteArrayAsync 方法返回 Task<byte[]> 实例,该实例表示在完成时生成字节数组的异步操作。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. 在操作完成之前,await 运算符将暂停 DownloadDocsMainPageAsync 方法。Until the operation completes, the await operator suspends the DownloadDocsMainPageAsync method. DownloadDocsMainPageAsync 暂停时,控件将返回到 Main 方法,该方法是 DownloadDocsMainPageAsync 的调用方。When DownloadDocsMainPageAsync gets suspended, control is returned to the Main method, which is the caller of DownloadDocsMainPageAsync. Main 方法将执行,直至它需要 DownloadDocsMainPageAsync 方法执行的异步操作的结果。The Main method executes until it needs the result of the asynchronous operation performed by the DownloadDocsMainPageAsync method. GetByteArrayAsync 获取所有字节时,将计算 DownloadDocsMainPageAsync 方法的其余部分。When GetByteArrayAsync gets all the bytes, the rest of the DownloadDocsMainPageAsync method is evaluated. 之后,将计算 Main 方法的其余部分。After that, the rest of the Main method is evaluated.

using System;
using System.Net.Http;
using System.Threading.Tasks;

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://docs.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.

上一个示例使用异步 Main 方法,该方法从 C# 7.1 开始可用。The preceding example uses the async Main method, which is possible beginning with C# 7.1. 有关详细信息,请参阅 Main 方法中的 await 运算符部分。For more information, see the await operator in the Main method section.

备注

有关异步编程的介绍,请参阅使用 async 和 await 的异步编程For an introduction to asynchronous programming, see Asynchronous programming with async and await. 利用 asyncawait 的异步编程遵循基于任务的异步模式Asynchronous programming with async and await follows the task-based asynchronous pattern.

只能在通过 async 关键字修改的方法、lambda 表达式匿名方法中使用 await 运算符。You can use the await operator only in a method, lambda expression, or anonymous method that is modified by the async keyword. 在异步方法中,不能在同步函数的主体、lock 语句块内以及不安全的上下文中使用 await 运算符。Within an async method, you cannot use the await operator in the body of a synchronous function, inside the block of a lock statement, and in an unsafe context.

await 运算符的操作数通常是以下其中一个 .NET 类型:TaskTask<TResult>ValueTaskValueTask<TResult>The operand of the await operator is usually of one of the following .NET types: Task, Task<TResult>, ValueTask, or ValueTask<TResult>. 但是,任何可等待表达式都可以是 await 运算符的操作数。However, any awaitable expression can be the operand of the await operator. 有关详细信息,请参阅 C# 语言规范中的可等待表达式部分。For more information, see the Awaitable expressions section of the C# language specification.

从 C# 8.0 开始,可使用 await foreach 语句来使用异步数据流。Beginning with C# 8.0, you can use the await foreach statement to consume an asynchronous stream of data. 有关详细信息,请参阅 C# 8.0 中的新增功能一文中的异步流部分。For more information, see the Asynchronous streams section of the What's new in C# 8.0 article.

如果表达式 t 的类型为 Task<TResult>ValueTask<TResult>,则表达式 await t 的类型为 TResultThe type of expression await t is TResult if the type of expression t is Task<TResult> or ValueTask<TResult>. 如果 t 的类型为 TaskValueTask,则 await t 的类型为 voidIf the type of t is Task or ValueTask, the type of await t is void. 在这两种情况下,如果 t 引发异常,则 await t 将重新引发异常。In both cases, if t throws an exception, await t rethrows the exception. 有关如何处理异常的详细信息,请参阅 try-catch 语句一文中的异步方法中的异常部分。For more information about exception handling, see the Exceptions in async methods section of the try-catch statement article.

asyncawait 关键字在 C# 5 和更高版本中都可用。The async and await keywords are available in C# 5 and later.

Main 方法中的 await 运算符await operator in the Main method

从 C# 7.1 开始,作为应用程序入口点的 Main 方法可以返回 TaskTask<int>,使其成为异步的,以便在其主体中使用 await 运算符。Beginning with C# 7.1, 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. 在较早的 C# 版本中,为了确保 Main 方法等待异步操作完成,可以检索由相应的异步方法返回的 Task<TResult> 实例的 Task<TResult>.Result 属性值。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. 对于不生成值的异步操作,可以调用 Task.Wait 方法。For asynchronous operations that don't produce a value, you can call the Task.Wait method. 有关如何选择语言版本的信息,请参阅 C# 语言版本管理For information about how to select the language version, see C# language versioning.

C# 语言规范C# language specification

有关详细信息,请参阅 C# 语言规范中的 Await 表达式部分。For more information, see the Await expressions section of the C# language specification.

请参阅See also