2013-07-25 19 views
22

に `await`を忘れません警告:私は考えてみましょうインタフェースメソッド呼び出し

using System.Threading.Tasks; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     C c = new C(); 
     c.FooAsync(); // warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. 
     ((I)c).FooAsync(); // No warning 
    } 
} 

class C : I 
{ 
    public async Task FooAsync() 
    { 
    } 
} 

interface I 
{ 
    Task FooAsync(); 
} 

私はcオブジェクトに直接非同期メソッドを呼び出す場合は、私は、コンパイラの警告が表示されます。ここにはバグが潜んでいる可能性があるので、私は警告がうれしいです。

しかし、インターフェイスメソッドで同じ呼び出しを行うと、警告は表示されません。このコードでバグを未解決にするのは簡単でしょう。

このような間違いをしないようにするにはどうすればよいですか?私自身を守るために適用できるパターンはありますか?

+1

良い質問...インターフェイスメソッドasyncをマークすることができないので、この場合はコンパイラから警告が出るとは思われません。たぶん、誰かがR#がそうしているかどうかを知っているかもしれません(またはプラグインがあります)。 –

+0

ReSharperはそれをキャッチしません。 – cadrell0

+0

ビルドプロセス中に[NDepend](http://www.ndepend.com/)がカスタム "CQL"クエリを実行するとそれが見つかる可能性がありますが、 'async'はコンパイラのトリックなので実際にはコンパイルされませんIL、私はそれを疑う。 –

答えて

6

メインは非同期ではないため、awaitは使用できません。これは、コンパイラのメッセージを少し混乱させるようです。呼び出しを実際の非同期メソッドに入れると、

static void Main(string[] args) 
{ 
    Task.Run(async() => 
         { 
          C c = new C(); 
          c.FooAsync(); 
          ((I) c).FooAsync(); 
         }); 
} 

...両方とも警告します。

10行目:この呼び出しは待機されていないため、呼び出しが完了する前に現在のメソッドの実行が継続されます。呼び出しの結果に 'await'演算子を適用することを検討してください。
行11:この呼び出しが待機されていないため、呼び出しが完了する前に現在のメソッドの実行が継続されます。呼び出しの結果に 'await'演算子を適用することを検討してください。

EDIT:非同期メソッド内Taskを返すすべてのメソッドは、あなたが待っていない限り警告したり、それらを割り当てますように思え。私たちは、非同期について言及していないインターフェイスで作業していることに注意してください。

interface I 
{ 
    Task FooAsync(); 
} 

static void Main(string[] args) 
{ 
    I i = null; 

    i.FooAsync();    // Does not warn 
    // await i.FooAsync(); // Can't await in a non async method 
    var t1 = i.FooAsync(); // Does not warn 

    Task.Run(async() => 
    { 
     i.FooAsync();   // Warns CS4014 
     await i.FooAsync(); // Does not warn 
     var t2 = i.FooAsync(); // Does not warn 
    }); 
} 
2

私は、コンパイルレベルでこの警告を出すことは不可能だと言っています。私のポイントをサポートするために、この例を見て:

interface I 
{ 
    Task Foo(); 
} 

class A : I 
{ 
    public Task Foo() 
    { 
    } 
} 

class B : I 
{ 
    public async Task Foo() 
    { 
    } 
} 

public class Program 
{ 
    private static void Main(string[] args) 
    { 
     I i; 

     if (Console.ReadLine() == "1") 
     { 
      i = new A(); 
     } 
     else i = new B(); 

     i.Foo(); 
    } 
} 

あなたが最初に考えたかもしれません。しかし、これは不条理な状況です。しかし、いくつかのデザインパターン(例はファクトリメソッド)は、派生クラスを非常に動的な方法でインスタンス化するメカニズムを使用しています。

したがって、メソッドが非同期かどうかをVSがどのように知ることができますか?

0

私はあなたがあまりにも多くを求めているかもしれないと思います。

interface I 
{ 
    void Foo(); 
} 

class C {} // does not implement I 

class Program 
{ 
    static void Main(string[] args) 
    { 
     C c = new C(); 
     ((I)c).Foo(); // Generates no compiler warning 
    } 
} 

それにもかかわらず、鋳造は、実行時に起こると、実行時にasyncなど何も(またはCILには)ありません。コンパイラは、async Task Foo()Task Foo()に変換し、state-machineのコルーチンとして実装します。

2

この警告するためのロジックがあると思われる:async方法で

  • は、Task -returningメソッドが呼び出されるたびに警告するが、結果はで
  • を無視し、通常の(非async)方法、Task -returning asyncメソッドが呼び出されたが、結果は例えば

無視されるたびに、この(無意味な)コードを見て警告:

Task NonAsyncMethod() 
{ 
    AsyncMethod(); // warnig 
    NonAsyncMethod(); // no warning 

    return null; // to make the code compile 
} 

async Task AsyncMethod() 
{ 
    AsyncMethod(); // warning 
    NonAsyncMethod(); // warning 
} 

あなたがインターフェイスと警告を取得していない理由はここにある:インターフェースメソッドではありません(とすることはできません)asyncとしてマークすること。

私はこの理由は、古くはasyncコードであると考えています。たとえば、task.ContinueWith()を呼び出してその結果を無視するのが一般的です。この場合でも警告が報告された場合、比較的古い量の正しいコードが突然警告になります。

バグの可能性が高い場合は、警告を出力する必要があります。報告されたケースは、そうでないケースよりもバグである可能性が高いと思います。私にとって、この行動は理にかなっています。

このような間違いをしないようにするには、Task - 返品方法をasyncコードから呼び出してください。

+1

"注意してください..."。うんざり、私は慎重では大嫌いです。 –

関連する問題