あなたが発見したように、VS11ではコンパイラはasync Main
メソッドを許可しません。これは、VS2010で非同期CTPを使用して許可されました(ただし、推奨されませんでした)。
特にasync / awaitと非同期コンソールプログラムに関する最近のブログ投稿があります。これが紹介記事の背景情報です。
「await」は、awaitableが完了していないことを確認すると、非同期で動作します。完了すると、残りのメソッドを実行するようにawaitableに指示し、asyncメソッドから戻ります。Awaitは、メソッドの残りの部分をawaitableに渡すときに現在のコンテキストもキャプチャします。
その後、awaitableが完了すると、(キャプチャされたコンテキスト内で)asyncメソッドの残りの部分が実行されます。
これが、コンソールプログラムで次の問題がある理由ですasync Main
。
紹介記事から、非同期メソッドは完了する前に呼び出し元に戻ることを覚えておいてください。これは、UIアプリケーション(メソッドは単にUIイベントループに戻る)とASP.NETアプリケーション(メソッドはスレッドから戻るが、要求を存続させる)で完全に機能します。コンソールプログラムではうまく機能しません。メインがOSに戻るため、プログラムは終了します。
1つの解決策は、独自のコンテキストを提供することです。非同期互換性のあるコンソールプログラムの「メインループ」です。
非同期CTPを備えたマシンがある場合は、My Documents \ Microsoft Visual Studio Async CTP \ Samples(C#Testing)Unit Testing \ AsyncTestUtilitiesGeneralThreadAffineContext
から使用できます。または、私のNito.AsyncEx NuGetパッケージから使用することもできます。AsyncContext
以下はを使用した例AsyncContext
です。GeneralThreadAffineContext
使い方はほぼ同じです:
using Nito.AsyncEx;
class Program
{
static void Main(string[] args)
{
AsyncContext.Run(() => MainAsync(args));
}
static async void MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
または、非同期作業が完了するまでメインコンソールスレッドをブロックするだけです。
class Program
{
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
の使用に注意してくださいGetAwaiter().GetResult()
。これにより、またはAggregateException
を使用した場合に発生するラッピングが回避されます。Wait()
Result
アップデート、2017年11月30日:のVisual Studio 2017のアップデート3(15.3)のように、言語がサポートされるようになりましたasync Main
-限り、それは返すようTask
かTask<T>
。したがって、これを行うことができます:
class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
セマンティクスGetAwaiter().GetResult()
は、メインスレッドをブロックするスタイルと同じように見えます。ただし、C#7.1の言語仕様はまだないため、これは前提にすぎません。