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 進行非同步程式設計。 使用 asyncawait 進行非同步程式設計時,會遵循以工作為基礎的非同步模式

您只能在以 async 關鍵字修改的方法、Lambda 運算式匿名方法中使用 await 運算子。 在非同步方法中,您無法在同步函式主體、lock 陳述式區塊和 unsafe 內容中使用 await 運算子。

await 運算子的運算元通常是下列其中一個 .NET 類型:TaskTask<TResult>ValueTaskValueTask<TResult>。 不過,任何可等候運算式都可以是 await 運算子的運算元。 如需詳細資訊,請參閱 C# 語言規格可等候運算式一節。

如果運算式 t 的類型為 Task<TResult>ValueTask<TResult>,則運算式 await t 的類型為 TResult。 如果 t 的類型為 TaskValueTask,則 await t 的類型為 void。 在這兩種情況下,如果 t 擲回例外狀況,await t 會重新擲回該例外狀況。

非同步串流和可處置項目

您可以使用 await foreach 陳述式取用資料的非同步資料流。 如需詳細資訊,請參閱反覆項目陳述式一文的foreach陳述式一節。

您可以使用 await using 陳述式處理非同步可處置的物件,即為實作 IAsyncDisposable 介面型別的物件。 如需詳細資訊,請參閱實作 DisposeAsync 方法一文的 Using async 可處置項目一節。

Main 方法中的 await 運算子

Main 方法 (應用程式進入點) 可以傳回 TaskTask<int>,使其成為非同步,讓您可以在其主體中使用 await 運算子。 在舊版 C# 中,若要確保 Main 方法會等候非同步作業完成,您可以擷取對應非同步方法所傳回 Task<TResult> 執行個體的 Task<TResult>.Result 屬性值。 針對不會產生值的非同步作業,您可以呼叫 Task.Wait 方法。 如需有關選取語言版本的資訊,請參閱 C# 語言版本

C# 語言規格

如需詳細資訊,請參閱 C# 語言規格Await 運算式一節。

另請參閱