await (C# 參考)await (C# Reference)

await 運算子會套用至非同步方法中的工作,以在執行方法中插入暫停點,直到等候的工作完成為止。The await operator is applied to a task in an asynchronous method to insert a suspension point in the execution of the method until the awaited task completes. 工作代表進行中的工作。The task represents ongoing work.

await 只能用於 async 關鍵字所修改的非同步方法中。can only be used in an asynchronous method modified by the async keyword. 這種方法是使用 async 修飾詞所定義,且通常包含一或多個 await 運算式,我們稱之為「非同步方法」。Such a method, defined by using the async modifier and usually containing one or more await expressions, is referred to as an async method.

注意

asyncawait 關鍵字是在 C# 5 中引入。The async and await keywords were introduced in C# 5. 如需非同步程式設計的簡介,請參閱使用 async 和 await 進行非同步程式設計For an introduction to async programming, see Asynchronous Programming with async and await.

套用了 await 運算子的工作,通常是呼叫傳回給實作工作式非同步模式的方法。The task to which the await operator is applied typically is returned by a call to a method that implements the Task-Based Asynchronous Pattern. 它們包括傳回 TaskTask<TResult>ValueTaskValueTask<TResult> 物件的方法。They include methods that return Task, Task<TResult>, ValueTask, and ValueTask<TResult> objects.

在下列範例中,HttpClient.GetByteArrayAsync 方法會傳回 Task<byte[]>In the following example, the HttpClient.GetByteArrayAsync method returns a Task<byte[]>. 這個工作可保證工作完成時,一定會產生實際位元組陣列。The task is a promise to produce the actual byte array when the task is complete. await 運算子會暫停執行,直到 GetByteArrayAsync 方法的工作完成為止。The await operator suspends execution until the work of the GetByteArrayAsync method is complete. 同時,控制權會返回 GetPageSizeAsync 的呼叫端。In the meantime, control is returned to the caller of GetPageSizeAsync. 在工作執行完成後,await 運算式評估為位元組陣列。When the task finishes execution, the await expression evaluates to a byte array.

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

public class Example
{
   public static void Main()
   {
      string[] args = Environment.GetCommandLineArgs();
      if (args.Length > 1)
         GetPageSizeAsync(args[1]).Wait();
      else
         Console.WriteLine("Enter at least one URL on the command line.");
   }

   private static async Task GetPageSizeAsync(string url)  
   {  
       var client = new HttpClient();  
       var uri = new Uri(Uri.EscapeUriString(url));
       byte[] urlContents = await client.GetByteArrayAsync(uri);
       Console.WriteLine($"{url}: {urlContents.Length/2:N0} characters");  
   }  
}
// The following call from the command line:
//    await1 http://docs.microsoft.com
// displays output like the following: 
//   http://docs.microsoft.com: 7,967 characters


重要

如需完整的範例,請參閱逐步解說:使用 Async 和 Await 存取 WebFor the complete example, see Walkthrough: Accessing the Web by Using Async and Await. 您可以從 Microsoft 網站的開發人員程式碼範例 下載此範例。You can download the sample from Developer Code Samples on the Microsoft website. 此範例位於 AsyncWalkthrough_HttpClient 專案中。The example is in the AsyncWalkthrough_HttpClient project.

如先前範例所示,如果將 await 套用至傳回 Task<TResult> 之方法呼叫的結果,則 await 運算式的類型為 TResultAs shown in the previous example, if await is applied to the result of a method call that returns a Task<TResult>, then the type of the await expression is TResult. 如果將 await 套用至傳回 Task 之方法呼叫的結果,則 await 運算式的類型為 voidIf await is applied to the result of a method call that returns a Task, then the type of the await expression is void. 下列範例會說明其間的差異。The following example illustrates the difference.

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

// await keyword used with a method that returns a ValueTask<TResult>.
TResult result = await AsyncMethodThatReturnsValueTaskTResult();

await 運算式不會封鎖其執行所在的執行緒。An await expression does not block the thread on which it is executing. 但是它會造成編譯器將其餘非同步方法註冊為所等候工作的接續。Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. 控制權接著會返回非同步方法的呼叫端。Control then returns to the caller of the async method. 當工作完成時,它會叫用其接續,並從中斷處繼續執行非同步方法。When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.

await 運算式只會出現在必須以 async 修飾詞標示的封入方法、Lambda 運算式或匿名方法的主體中。An await expression can occur only in the body of its enclosing method, lambda expression, or anonymous method, which must be marked with an async modifier. await 這個詞彙只在該內容中作為關鍵字。The term await serves as a keyword only in that context. 在其他內容中,它會解譯為識別項。Elsewhere, it is interpreted as an identifier. 在方法、Lambda 運算式或匿名方法中,await 運算式不能出現在同步函式、查詢運算式、lock 陳述式的區塊,或是 unsafe 內容中。Within the method, lambda expression, or anonymous method, an await expression cannot occur in the body of a synchronous function, in a query expression, in the block of a lock statement, or in an unsafe context.

例外狀況Exceptions

大部分的非同步方法會傳回 TaskTask<TResult>Most async methods return a Task or Task<TResult>. 傳回的工作屬性會隨附其狀態和記錄的相關資訊,例如工作是否完成、非同步方法是否造成例外狀況或已取消,以及最終結果為何。The properties of the returned task carry information about its status and history, such as whether the task is complete, whether the async method caused an exception or was canceled, and what the final result is. await 運算子透過呼叫 GetAwaiter 方法所傳回之物件上的方法,來存取這些屬性。The await operator accesses those properties by calling methods on the object returned by the GetAwaiter method.

如果您在等候工作傳回非同步方法時導致例外狀況,await 運算子會重新擲回例外狀況。If you await a task-returning async method that causes an exception, the await operator rethrows the exception.

如果您等候已取消的工作傳回非同步方法,則 await 運算子會重新擲回 OperationCanceledExceptionIf you await a task-returning async method that's canceled, the await operator rethrows an OperationCanceledException.

處於錯誤狀態的單一工作可能反映多個例外狀況。A single task that is in a faulted state can reflect multiple exceptions. 例如,工作可能是對 Task.WhenAll 呼叫的結果。For example, the task might be the result of a call to Task.WhenAll. 當您等候這類工作時,await 作業只會重新擲回其中一個例外狀況。When you await such a task, the await operation rethrows only one of the exceptions. 不過,您無法預測重新擲回哪個例外狀況。However, you can't predict which of the exceptions is rethrown.

如需非同步方法中錯誤處理的範例,請參閱 try-catchFor examples of error handling in async methods, see try-catch.

範例Example

下列範例會傳回頁面的總字元數,這些頁面的 URL 會傳遞給它當做命令列引數。The following example returns the total number of characters in the pages whose URLs are passed to it as command line arguments. 本例會呼叫 GetPageLengthsAsync 方法,這會以 async 關鍵字標示。The example calls the GetPageLengthsAsync method, which is marked with the async keyword. GetPageLengthsAsync 方法接著會使用 await 關鍵字來等候對 HttpClient.GetStringAsync 方法的呼叫。The GetPageLengthsAsync method in turn uses the await keyword to await calls to the HttpClient.GetStringAsync method.

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

class Example
{
   static async Task Main()
   {
      string[] args = Environment.GetCommandLineArgs();
      if (args.Length < 2)
         throw new ArgumentNullException("No URIs specified on the command line.");

      // Don't pass the executable file name
      var uris = args.Skip(1).ToArray();

      long characters = await GetPageLengthsAsync(uris);
      Console.WriteLine($"{uris.Length} pages, {characters:N0} characters");
   }

   private static async Task<long> GetPageLengthsAsync(string[] uris)
   {
      var client = new HttpClient();
      long pageLengths = 0;

      foreach (var uri in uris)
      {
         var escapedUri = new Uri(Uri.EscapeUriString(uri));
         string pageContents = await client.GetStringAsync(escapedUri);
         Interlocked.Add(ref pageLengths, pageContents.Length);
      }
      
      return pageLengths;
   }
}

上述範例使用 C# 7.1,可支援 async Main 方法The preceding example uses C# 7.1, which supports the async Main method. 由於較舊的 C# 版本不支援會傳回 TaskTask<TResult> 的應用程式進入點,因此您無法將 async 修飾詞套用至 Main 方法並等候 GetPageLengthsAsync 方法呼叫。Because earlier C# versions don't support application entry points that return Task or Task<TResult>, you cannot apply the async modifier to the Main method and await the GetPageLengthsAsync method call. 在此情況下,您可以透過擷取 Task<TResult>.Result 屬性的值,確保 Main 方法會等候非同步作業完成。In that case, you can ensure that the Main method waits for the async operation to complete by retrieving the value of the Task<TResult>.Result property. 針對不傳回值的工作,您可以呼叫 Task.Wait 方法。For tasks that do not return a value, you can call the Task.Wait method. 如需有關選取語言版本的資訊,請參閱選取 C# 語言版本For information about how to select the language version, see Select the C# language version.

另請參閱See also