await(C# 参考)

await 运算符在异步方法应用于任务,以挂起执行方法,直到所等待的任务完成。任务表示正在进行的工作。

在其中使用 await 的异步方法必须通过 async 关键字进行修改。使用 async 修饰符定义并且通常包含一个或多个 await 表达式的这类方法称为异步方法

注意
asyncawait 关键字是在 Visual Studio 2012 中引入的。有关异步编程的说明,请参阅使用 Async 和 Await 的异步编程(C# 和 Visual Basic)

应用 await 运算符的任务通常是实现基于任务的异步模式的方法调用的返回值。示例包括 TaskTask<TResult> 类型的值。

在以下代码中,HttpClient 方法 GetByteArrayAsync 返回 Task<byte[]> (getContentsTask)。当任务完成时,任务约定生成实际字节数组。 await 运算符应用于 getContentsTask 以在 SumPageSizesAsync 中挂起执行,直到 getContentsTask 完成。同时,控制权会返回给 SumPageSizesAsync 的调用方。当 getContentsTask 完成之后,await 表达式计算为字节数组。


private async Task SumPageSizesAsync()
{
    // To use the HttpClient type in desktop apps, you must include a using directive and add a
    // reference for the System.Net.Http namespace.
    HttpClient client = new HttpClient();
    // . . .
    Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
    byte[] urlContents = await getContentsTask;

    // Equivalently, now that you see how it works, you can write the same thing in a single line.
    //byte[] urlContents = await client.GetByteArrayAsync(url);
    // . . .
}
System_CAPS_important重要事项
有关完整示例,请参阅演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)。可以从 Microsoft 网站上的开发人员代码示例下载该示例。该示例处于 AsyncWalkthrough_HttpClient 项目中。

如前面的示例中所示,如果 await 应用于返回 Task<TResult> 的方法调用结果,则 await 表达式的类型为 TResult。如果 await 应用于返回 Task 的方法调用结果,则 await 表达式的类型为 void。以下示例演示了差异。

// Keyword await used with a method that returns a Task<TResult>.
TResult result = await AsyncMethodThatReturnsTaskTResult();

// Keyword await used with a method that returns a Task.
await AsyncMethodThatReturnsTask();

await 表达式不阻止正在执行它的线程。而是使编译器将剩下的异步方法注册为等待任务的延续任务。控制权随后会返回给异步方法的调用方。任务完成时,它会调用其延续任务,异步方法的执行会在暂停的位置处恢复。

await 表达式只能在由 async 修饰符标记的立即封闭方法体、lambda 表达式或异步方法中出现。术语“await”在该上下文中仅用作关键字。在其他位置,它会解释为标识符。在方法、lambda 表达式或匿名方法中,await 表达式不能在同步函数体、查询表达式、lock 语句块或不安全上下文中出现。

异常

大多数异步方法返回 TaskTask<TResult>。返回任务的属性携带有关其状态和历史记录的信息,如任务是否完成、异步方法是否导致异常或已取消以及最终结果是什么。 await 运算符可访问这些属性。

如果等待的任务返回异步方法导致异常,则 await 运算符会重新引发异常。

如果等待的任务返回异步方法取消,则 await 运算符会重新引发 OperationCanceledException

处于故障状态的单个任务可以反映多个异常。例如,任务可能是对 Task.WhenAll 调用的结果。等待此类任务时,等待操作仅重新引发异常之一。但是,无法预测重新引发的异常。

有关异步方法中的错误处理的示例,请参阅 try-catch(C# 参考)

下面的 Windows 窗体示例阐释如何在异步方法 WaitAsynchronouslyAsync 中使用 await。将该方法的行为与 WaitSynchronously 的行为进行对比。如果未向任务应用 await 运算符,WaitSynchronously 就会同步运行,而不管其定义中是否使用了 async 修饰符和在主体中是否调用了 Thread.Sleep


private async void button1_Click(object sender, EventArgs e)
{
    // Call the method that runs asynchronously.
    string result = await WaitAsynchronouslyAsync();

    // Call the method that runs synchronously.
    //string result = await WaitSynchronously ();

    // Display the result.
    textBox1.Text += result;
}

// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
    await Task.Delay(10000);
    return "Finished";
}

// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
    // Add a using directive for System.Threading.
    Thread.Sleep(10000);
    return "Finished";
}

请参阅

使用 Async 和 Await 的异步编程(C# 和 Visual Basic)

演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)

async(C# 参考)