web-dev-qa-db-ja.com

基本クラスで仮想非同期メソッドを使用しても大丈夫ですか?

私はいくつかのコードで作業していますが、そこではロジックとコードが非常に似ている2つのクラスがあります。両方のクラスにprotected async void LoadDataAsync()メソッドがあります。
現在、私はそれをリファクタリングし、共有ロジックを基本クラスに移動することを考えています。
virtual async基本クラスのメソッドと派生クラスでそれをオーバーライドしますか?
問題はありますか?
私のコードは次のようになります。

public class Base
{
   protected virtual async void LoadDataAsync() {}
}

public class Derived : Base
{
   protected override async void LoadDataAsync()
   {
       // awaiting something
   }
}

同様の(同じではありません) 質問はすでに尋ねられました.

41

短い答え

  • virtualメソッドmayasyncとしてマークされる
  • abstractメソッドできないasyncとしてマークされる

この理由は、asyncは実際にはメソッドシグネチャの一部ではないからです。メソッド本体自体のコンパイルの処理方法をコンパイラに指示するだけです(メソッドのオーバーライドには適用されません)。抽象メソッドにはメソッド本体がないため、async修飾子を適用しても意味がありません。

長い答え

基本クラスがメソッドのデフォルトの実装を提供するが、作業を行う必要がない場合は、基本クラスの現在の署名ではなく、以下をお勧めします。

protected virtual Task LoadDataAsync() {
  return Task.FromResult(default(object));
}

実装からの主な変更点は次のとおりです。

  1. 戻り値をvoidからTaskに変更します(asyncは実際には戻り値型の一部ではないことに注意してください)。 voidを返すのとは異なり、Taskが返される場合、呼び出しコードは次のいずれかを実行できます。
    • 操作が完了するのを待ちます
    • タスクのステータスを確認します(完了、キャンセル、障害)
  2. メソッドはasyncを何も必要としないため、await修飾子の使用は避けてください。代わりに、既に完了したTaskインスタンスを返すだけです。このメソッドをオーバーライドするメソッドは、必要に応じてasync修飾子を使用できます。
70
Sam Harwell

はい、問題ありませんが、async Taskの代わりにasync voidを使用する必要があります。 理由を説明するMSDN記事 があります。

19
Stephen Cleary