await(C# 参考)
await 运算符应用于一个异步方法中的任务以挂起该方法的执行,直到等待任务完成。 表示正在进行的工作的任务。
使用 await 的异步方法必须由异步关键字修改。 由使用 async 修饰符定义且通常包含一个或多个 await 表达式的此类方法称为异步方法。
备注
在 Visual Studio 2012 中引入 async 和 await 关键字。有关异步编程的介绍,请参见 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)。
应用 await 运算符的任务通常是对实现基于任务的异步模式 的方法的调用中的返回值。 示例包括类型 Task 或 Task 的值。
在以下代码中,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);
// . . .
}
重要
有关完整的示例,请参见演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)。您可以在 Microsoft 网站上从开发人员代码示例中下载示例。此示例在 AsyncWalkthrough_HttpClient 项目中。
正如之前的示例所示,如果 await 应用于返回到 Task<TResult> 的方法调用的结果,那么 await 表达式的类型是 TResult。 如果将 await 应用于返回一个 Task 的方法调用结果,则 await 表达式的类型无效。 下面的示例演示这种差异。
// 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 表达式只发生在一个立即封闭方法的主体、lambda 表达式或由 async 修饰符标记的匿名方法中。 等待术语仅在该上下文中用作关键字。 在其他地方,其解释为标识符。 在方法、Lambda 表达式或匿名方法中,await 表达式不会出现在同步函数主体中、查询表达式中、异常处理语句的 catch 或 finally 块中,lock 语句的块中或者不安全的环境中。
异常
大多数异步方法返回 Task 或 Task。 返回任务的属性承载有关其状态和历史记录的信息,例如任务是否已完成,异步方法是否引发异常或已取消,以及最终结果如何。 await 运算符访问那些属性。
如果等待导致异常的任务返回的异步方法,await 运算符会再次引发异常。
如果等待取消的任务返回的异步方法,await 运算符再次引发 OperationCanceledException。
处于出错状态的单个任务可能反映出多个异常。 例如,该任务可能是对 Task.WhenAll 调用的结果。 当您等待此类任务时,await 操作只能再次引发异常中的一个。 但是,您不能预测哪些异常是重新引发的。
有关错误处理同步方法的示例,请参见 try-catch(C# 参考)。
示例
以下 Windows Forms 示例说明了异步方法 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 访问 Web(C# 和 Visual Basic)