await 演算子 - タスクの完了を非同期に待機します

await 演算子では、そのオペランドによって表わされる非同期操作が完了するまで、外側の async メソッドの評価が保留になります。 非同期操作が完了すると、await 演算子から演算の結果が返されます (結果がある場合)。 既に完了している操作を表すオペランドに await 演算子が適用されると、外側のメソッドを保留にすることなく、演算の結果がすぐに返されます。 await 演算子では、async メソッドを評価するスレッドがブロックされません。 await 演算子によって外側の async メソッドが保留になるとき、メソッドの呼び出し元にコントロールが戻ります。

次の例では、完了時にバイト配列を生成する非同期操作を表わす Task<byte[]> インスタンスが、HttpClient.GetByteArrayAsync メソッドから返されます。 操作が完了するまで、await 演算子によって DownloadDocsMainPageAsync メソッドが保留になります。 DownloadDocsMainPageAsync が保留になると、DownloadDocsMainPageAsync の呼び出し元である Main メソッドにコントロールが返されます。 DownloadDocsMainPageAsync メソッドで実行される非同期操作の結果が必要になるまで Main メソッドが実行されます。 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 式のオペランドは、タスクが完了したときに通知を提供する必要があります。 一般に、デリゲートは、タスクが正常に完了するか失敗したときに呼び出されます。 await C# 言語仕様のセクションでは、これらの通知の実装方法について詳しく説明します。

前の例では、async Main メソッドを使用しています。 詳細は、「await operator in the Main method」 (Main メソッドの await 演算子) セクションを参照してください。

注意

非同期プログラミングの概要については、「async および await を使用した非同期プログラミング」を参照してください。 asyncawait による非同期プログラミングは、タスクベースの非同期パターンに続きます。

メソッド、ラムダ式async キーワードで修飾される匿名メソッドでのみ await 演算子を使用できます。 async メソッド内では、同期関数の本文の中、lock ステートメントのブロックの内部、安全でないコンテキストの中で await 演算子を使用することはできません。

.NET の型として TaskTask<TResult>ValueTaskValueTask<TResult> がありますが、await 演算子のオペランドはそのいずれかになります。 ただし、待機可能な式であれば 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 メソッドの実装」記事の「非同期の破棄可能の使用」を参照してください。

Main メソッドの await 演算子

アプリケーション エントリ ポイントである Main メソッドから Task または Task<int> が返され、その本文で await 演算子を使用できるよう、非同期にすることができます。 以前の C# バージョンでは、非同期操作の完了を Main メソッドが待つようにする目的で、対応する async メソッドから返される Task<TResult> インスタンスの Task<TResult>.Result プロパティの値を取得できます。 値を生成しない非同期操作の場合、Task.Wait メソッドを呼び出すことができます。 言語のバージョンを選択する方法については、「C# 言語のバージョン管理」を参照してください。

C# 言語仕様

詳細については、「C# 言語仕様」の「Await 式」セクションを参照してください。

関連項目