await 運算子:以非同步方式等候工作完成
await
運算子會暫停封入非同步方法的評估,直到其運算元所代表的非同步作業完成為止。 當非同步作業完成時,await
運算子會傳回作業的結果 (如果有的話)。 當 await
運算子套用至代表已完成作業的運算元時,它會立即傳回作業的結果,而不會暫停封入方法。 await
運算子不會封鎖評估非同步方法的執行緒。 當 await
運算子暫停封入非同步方法時,控制項會返回方法的呼叫端。
在下列範例中,HttpClient.GetByteArrayAsync 方法會傳回 Task<byte[]>
執行個體,代表在完成時產生位元組陣列的非同步作業。 await
運算子會暫停 DownloadDocsMainPageAsync
方法,直到作業完成為止。 當 DownloadDocsMainPageAsync
暫停時,控制權會返回 Main
方法,也就是 DownloadDocsMainPageAsync
的呼叫端。 Main
方法會執行直到需要 DownloadDocsMainPageAsync
方法所執行的非同步作業結果為止。 當 GetByteArrayAsync 取得所有位元組時,會評估 DownloadDocsMainPageAsync
方法的其餘部分。 之後,會評估 Main
方法的其餘部分。
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://learn.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.
await
運算式的運算元必須在工作完成時提供通知。 一般而言,不論工作順利或不順利完成,都會叫用委派。 C# 語言規格的 await
區段提供如何實作這些通知的詳細資料。
上述範例會使用 非同步Main
方法。 如需詳細資訊,請參閱 Main 方法中的 await 運算子一節。
注意
如需非同步程式設計的簡介,請參閱使用 async 和 await 進行非同步程式設計。 使用 async
和 await
進行非同步程式設計時,會遵循以工作為基礎的非同步模式。
您只能在以 async 關鍵字修改的方法、Lambda 運算式或匿名方法中使用 await
運算子。 在非同步方法中,您無法在同步區域函式主體、lock 陳述式區塊和 unsafe 內容中使用 await
運算子。
await
運算子的運算元通常是下列其中一個 .NET 類型:Task、Task<TResult>、ValueTask 或 ValueTask<TResult>。 不過,任何可等候運算式都可以是 await
運算子的運算元。 如需詳細資訊,請參閱 C# 語言規格的可等候運算式一節。
如果運算式 t
的類型為 Task<TResult> 或 ValueTask<TResult>,則運算式 await t
的類型為 TResult
。 如果 t
的類型為 Task 或 ValueTask,則 await t
的類型為 void
。 在這兩種情況下,如果 t
擲回例外狀況,await t
會重新擲回該例外狀況。
非同步串流和可處置項目
您可以使用 await foreach
陳述式取用資料的非同步資料流。 如需詳細資訊,請參閱反覆項目陳述式一文的foreach
陳述式一節。
您可以使用 await using
陳述式處理非同步可處置的物件,即為實作 IAsyncDisposable 介面型別的物件。 如需詳細資訊,請參閱實作 DisposeAsync 方法一文的 Using async 可處置項目一節。
Main 方法中的 await 運算子
Main
方法 (應用程式進入點) 可以傳回 Task
或 Task<int>
,使其成為非同步,讓您可以在其主體中使用 await
運算子。 在舊版 C# 中,若要確保 Main
方法會等候非同步作業完成,您可以擷取對應非同步方法所傳回 Task<TResult> 執行個體的 Task<TResult>.Result 屬性值。 針對不會產生值的非同步作業,您可以呼叫 Task.Wait 方法。 如需有關選取語言版本的資訊,請參閱 C# 語言版本。
C# 語言規格
如需詳細資訊,請參閱 C# 語言規格的 Await 運算式一節。