await(C# 参考)

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

使用 await 的异步方法必须由异步关键字修改。 由使用 async 修饰符定义且通常包含一个或多个 await 表达式的此类方法称为异步方法。

备注

在 Visual Studio 2012 中引入 async 和 await 关键字。有关异步编程的介绍,请参见 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)

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

在以下代码中,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 语句的块中或者不安全的环境中。

异常

大多数异步方法返回 TaskTask。 返回任务的属性承载有关其状态和历史记录的信息,例如任务是否已完成,异步方法是否引发异常或已取消,以及最终结果如何。 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)

参考

async(C# 参考)

概念

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