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://video2.skills-academy.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
による非同期プログラミングは、タスクベースの非同期パターンに続きます。
メソッド、ラムダ式、async キーワードで修飾される匿名メソッドでのみ await
演算子を使用できます。 async メソッド内では、同期ローカル関数の本文の中、lock ステートメントのブロックの内部、安全でないコンテキストの中で await
演算子を使用することはできません。
.NET の型として Task、Task<TResult>、ValueTask、ValueTask<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 式」セクションを参照してください。
関連項目
.NET