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


16

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

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

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

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

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



呼び出し側がオーバーライドされたメソッドを待つことを正確に禁止するものは何ですか?障害はありません。
マーティンマート

@MartinMaatを返すメソッドのみ待機できTaskます。
デレクエルキンズは

おそらく、それは私が気付いていなかったすばらしい点だろう。確認する必要がありますが、待機せずに非非同期メソッドを呼び出すことに関するVS警告を思い出せません。
ピーターT.ラコームジュニア

回答:


16

非同期キーワードが可能にメソッドを使用するにはawait、その定義内の構文を。非同期メソッドであるかどうかに関係なくawaitTask型を返す任意のメソッドで実行できます。

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

呼び出し元に、async T方法は戻り、正常な方法であるT(これらに限定されているvoidTaskまたはTask<A>)。それが非同期メソッドであることは、インターフェースの一部ではありません。次のコードは違法であることに注意してください。

interface IFoo {
    async void Bar();
}

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

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

私は場合はやった、通常は非同期であることをインターフェイスまたは親クラスのメソッドを意図し、私が使用できないasyncことを伝えるために。await構文を使用して実装する場合は、非同期オーバーライドメソッド(親クラスの場合)が必要になります。


1
まったく言及overrideしていませんが、それが問題です。
ネイサンタギー16年

4
@NathanTuggy答えの全体のポイントは、asyncメソッドのインターフェイスを変更せず、その定義で構文的に許可されているものだけを変更することです。そのため、オーバーライドかどうかは完全に無関係です。
デレクエルキンズは

1
誰もが関連するすべてをすでに知っていると仮定するのではなく、それを説明してください。
ネイサンタギー16年

2
@NathanTuggy私はそれを説明したと思う。あなたが混乱している特定の質問をすることができますか、または別の混乱した人が尋ねると想像してください。追加できると思う唯一のことは、async修飾子は実装にのみ適用できることを指摘することです。インターフェイスでメソッド非同期を宣言することはできません。たとえば、メソッドが非同期であるかどうかはインターフェイスの一部ではないことを強調します。
デレクエルキンズは

5
答えに説明入れてください。長い目で見ればそれはコメントの目的ではありません。
ネイサンタギー16年

10

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.