1. ホーム
  2. c#

[解決済み】コンソールアプリのMainメソッドにasync修飾子を指定できない。

2022-03-23 02:30:47

質問

を使った非同期プログラミングは初めてです。 async モディファイアを使用します。私は、どのようにして私の Main メソッドが実際に非同期で実行されます。

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = bs.GetList();
    }
}

public class Bootstrapper {

    public async Task<List<TvChannel>> GetList()
    {
        GetPrograms pro = new GetPrograms();

        return await pro.DownloadTvChannels();
    }
}

これはトップから非同期で実行されていないことは分かっているのですが "" 指定できないので async モディファイアを Main メソッド内でコードを実行するにはどうすればよいですか? main 非同期で?

どのように解決するのですか?

あなたが発見したように、VS11ではコンパイラは async Main メソッドを使用します。これは、VS2010 の Async CTP では許可されていました (しかし、決して推奨されていませんでした)。

私は最近のブログ記事で async/await 非同期コンソールプログラム 特に 以下は、イントロポストからの背景情報です。

<ブロッククオート

await"は、awaitableが完了していないことを確認すると、非同期的に行動します。awaitが完了したらメソッドの残りを実行するように指示し、その後 リターン を非同期メソッドから取得します。Awaitはまた、現在の コンテキスト メソッドの残りをawaitableに渡すとき。

その後、awaitable が完了すると、非同期メソッドの残りを実行します (キャプチャしたコンテキスト内で)。

ここで、なぜこれが問題になるかというと、Consoleプログラムにおいて async Main :

イントロダクションの記事で、非同期メソッドが 返す を呼び出し元へ送信します。これはUIアプリケーション(メソッドはUIイベントループに戻るだけ)やASP.NETアプリケーション(メソッドはスレッドから戻るがリクエストは維持される)では完璧に機能します。しかし、Consoleプログラムではあまりうまくいきません。MainはOSに戻るので、プログラムは終了してしまいます。

1つの解決策は、あなた自身のコンテキスト、つまり非同期互換性のあるコンソール・プログラム用の "メイン・ループ" を提供することです。

Async CTPが搭載されているマシンをお持ちの方は GeneralThreadAffineContext から My DocumentsMicrosoft Visual Studio Async CTPSamples(C# Testing) Unit Testing . または、次のように使用することもできます。 AsyncContext から 私の Nito.AsyncEx NuGet パッケージ .

を使った例です。 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();
    }
}

また、非同期処理が完了するまで、Console のメインスレッドをブロックすることもできます。

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 Update 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の言語仕様がまだないので、これはあくまで仮定に過ぎません。