web-dev-qa-db-ja.com

C#でオーバーライドを非同期にできるのはなぜですか?

C#では、メソッドをオーバーライドすると、元のメソッドがそうでなかったときにオーバーライドを非同期にすることが許可されます。これは形が悪いようです。

これに私を導いた例はこれです—私は負荷テストの問題を支援するために連れてこられました。約500人の同時ユーザーで、ログインプロセスはリダイレクトループで機能しなくなります。 IISは、「非同期操作がまだ保留中に非同期モジュールまたはハンドラーが完了しました」というメッセージで例外をログに記録していました。検索の結果、誰かが悪用していると思いましたasync voidですが、ソースをすばやく検索しても何も見つかりませんでした。

悲しいことに、 'async\s [^ T]'のようなものを探すべきだったときに、私は 'async\svoid'(正規表現検索)を検索していました(タスクが完全に修飾されていないと仮定すると、ポイントがわかります)。

後で見つけたのはasync override void onActionExecuting(...ベースコントローラで。明らかにそれが問題である必要があり、それが問題でした。これを修正する(現時点では同期にする)ことで問題が解決しました。

質問に戻る:呼び出し側のコードがそれを待てないのに、なぜオーバーライドを非同期としてマークできるのですか?

17

async キーワードを使用すると、methodがその定義内でawait構文を使用できるようになります。非同期メソッドかどうかに関係なく、awaitタイプを返すすべてのメソッドでTaskを実行できます。

voidは、非同期メソッドの正当な(ただし discouraged )戻り型なので、なぜ許可されないのですか?外から見ると、asyncは、それなしでは実行できなかった機能を有効にしていません。問題のあるメソッドは、非同期になることなくまったく同じように動作するように記述されている可能性があります。その定義はもっと冗長だったでしょう。

呼び出し元にとって、async TメソッドはTvoidTask、またはTask<A>に限定される)を返す通常のメソッドです。非同期メソッドであることはインターフェースの一部ではありません。次のコードは不正であることに注意してください。

interface IFoo {
    async void Bar();
}

それ(または抽象クラスの同様のコード)は、VS2012で次のエラーメッセージを生成します。

'async'修飾子は、ステートメント本文を持つメソッドでのみ使用できます

Ididがインターフェイスまたは親クラスのメソッドを通常非同期にすることを意図している場合、asyncを使用してそれを通信することはできません。 await構文を使用して実装する場合は、非同期オーバーライドメソッド(親クラスの場合)が必要です。

17

Asyncキーワードの唯一の目的は、その関数の本体内で待機することをキーワードにすることです。これは、待機機能を追加しても既存のコードが壊れないようにするために必要です。マイクロソフトは、待機オプションを利用することを決定しました。 asyncとマークされていない関数の場合、問題なくawaitという名前の変数を定義できます。

したがって、非同期は関数のシグネチャの一部ではなく、生成されたILコードでは意味を持ちません。コンパイラが関数を正しくコンパイルする方法を知るのは、厳密にそこにあります。また、Task、Task <T>、またはvoidのみが返されるようにコンパイラーに指示します。

10
Eric Johnson