await 演算子では、そのオペランドによって表わされる非同期操作が完了するまで、外側の async メソッドの評価が保留になります。 非同期操作が完了すると、await 演算子から演算の結果が返されます (結果がある場合)。 既に完了している操作を表すオペランドに await 演算子が適用されると、外側のメソッドを保留にすることなく、演算の結果がすぐに返されます。
await 演算子では、async メソッドを評価するスレッドがブロックされません。
await 演算子によって外側の async メソッドが保留になるとき、メソッドの呼び出し元にコントロールが戻ります。
次の例では、完了時にバイト配列を生成する非同期操作を表わす 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 式のオペランドは、タスクが完了したときに通知を提供する必要があります。 一般に、デリゲートは、タスクが正常に完了するか失敗したときに呼び出されます。
await C# 言語仕様のセクションでは、これらの通知の実装方法について詳しく説明します。
前の例では、async Main メソッドを使用しています。 詳細は、「await operator in the Main method」 (Main メソッドの await 演算子) セクションを参照してください。
注意
非同期プログラミングの概要については、「async および await を使用した非同期プログラミング」を参照してください。
async と await による非同期プログラミングは、タスクベースの非同期パターンに続きます。
メソッド、await、async キーワードで修飾される匿名メソッドでのみ 演算子を使用できます。 async メソッド内では、同期ローカル関数の本文の中、awaitのブロックの内部、安全でないコンテキストの中で 演算子を使用することはできません。
.NET の型として await、Task、Task<TResult>、ValueTask がありますが、ValueTask<TResult> 演算子のオペランドはそのいずれかになります。 ただし、待機可能な式であれば await 演算子のオペランドになります。 詳細については、「C# 言語仕様」の「待機可能な式」セクションを参照してください。
式 await t の型が TResult または t の場合、式 Task<TResult> の型は ValueTask<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>.Result インスタンスの Task<TResult> プロパティの値を取得できます。 値を生成しない非同期操作の場合、Task.Wait メソッドを呼び出すことができます。 言語のバージョンを選択する方法については、「C# 言語のバージョン管理」を参照してください。
C# 言語仕様
詳細については、「C# 言語仕様」の「Await 式」セクションを参照してください。
関連項目
.NET