2016-10-05 48 views
2

コンパイラ警告CS4014(結果を待つことなく、非同期メソッドを呼び出す)と呼ばれる方法が参照アセンブリにあるときに、ビルド時に警告として放出されていない間に放出されません。コンパイラ警告CS4014は、ビルド

呼び出されたメソッドが同じアセンブリ内にある場合、警告は正しく送出されます。

コンパイラの警告は、両方のプロジェクトが同じソリューションに含まれている場合、Visual Studioでと表示されます。

違いは、両方のアセンブリへのソースコードを有する唯一のコンパイル参照アセンブリおよびVisual Studioを持つコンパイラによって引き起こされているように見えます。

質問は次のとおりです。なぜこれらの2つの異なる動作がありますか?コンパイル中にCS4014の警告を発する方法はありますか?

TestClassLibrary1

public class Class1 
{ 
    public static async Task<string> DoSomething() 
    { 
     return await Task.FromResult("test"); 
    } 
} 

TestClassLibrary2(TestClassLibrary1を参照)

public class Class2 
{ 
    public void CallingDoSomething() 
    { 
     Class1.DoSomething(); 
    } 
} 

これらのプロジェクトをコンパイル:

は、この動作の設定に2つのクラスライブラリ、両方持つ一つのコードファイルを複製するには警告なしで完了します。 Visual Studioで同じソリューションでそれらを開くと、エラーリストに1エラーが表示され、 Class1.DoSomething()の下に赤い波線が表示されます。

+0

アセンブリをどのようにコンパイルしますか?使用しているステートメントを表示できますか? –

+0

Visual Studio - >ビルドソリューションを使用してアセンブリをコンパイルしています。両方のプロジェクトは、すべての警告とともにコンパイルされます( '/ warn:4')。それが助けになるなら、私はcsc.exeへの引数を貼り付けることができますが、それらはかなり長いです。 –

+0

さて、私はあなたが手でビルを走っていると思った。 –

答えて

4

async修飾子を使用すると、(awaitで)より便利Taskを返すコードを記述することができますが、それはIL *には表現を持っていません。コンパイルされたアセンブリでは、このメソッドは単にコンパイラに対してpublic static Task<string> DoSomethingのように見え、結果を待たずにこれらのメソッドを呼び出すことは、メソッドが同じアセンブリに存在する場合でも警告をトリガしません。 Class1.DoSomethingをタスクを返す他のものに置き換え、待たなければならない(例えばTask.Delay(2000))と、同様にコンパイラが警告しないことがわかります。しかし、すべてのソースコードが利用可能になると、コンパイラ(およびコンパイラはRoslynを意味します)は、修飾子が依然として構文木の一部であるため、このメソッドをasyncと識別できます。

asyncを使用して記述されたかどうかにかかわらず、結果を使用せずにTaskを返すメソッドを呼び出すと、コンパイラは常に警告しません。良い質問。 Task(例えばTask.WhenAllに渡したいので)を待つことを待たない多くの合法的なシナリオがありますが、これらのすべてにはTaskを格納することが含まれ、警告は発生しません。 Taskを返すメソッドを呼び出し、その結果を破棄することは、完全にこの警告は、最初の場所に存在する理由である、ほぼ確実に間違いである(そして、それは意図的だとき、警告を抑制するelegant waysがあります)。

私はこの警告の実装は微調整(または新しい警告の置き換え)を使用することができます疑いが、コンパイラに取り組んで唯一の人々は確かにそれを知っているだろう。


*:これは実際には当てはまりません。 asyncのメソッドには、より便利なデバッグのためにAsyncStateMachineAttributeが適用されています。しかし、何らかの理由でコンパイラはアセンブリ全体でasyncメソッドを識別するためにこれを使用しません。間違いなく、Taskの点で特にasyncについて特別なことはありません。しかし、CS4104の規定されたセマンティクスを正確に保持したい場合(asyncメソッドの結果が使用されていない場合に警告する)、これがその方法の1つになります。

+0

恐らく、タスクを起動するためのTask.Run()の蔓延は、偽陽性率が警告を無条件にするには高すぎることを意味します。 –

+0

偉大な答え、ありがとう!私は、MassTransitというライブラリを使って作業しています。このライブラリは、内部的にタスクを格納し、同じタスクを返すパターンを使用しています。呼び出し元には、次の2つのオプションがあります。1.返されたタスクが正常に完了したことを確認するか、または2. MassTransitがタスクを待って例外を処理させる。したがって、待たずにメソッドを呼び出す方法が正当に使用される可能性があります。 Roslyn GitHubレポヘルプの問題を提起しますか? –

+0

@BenjaminWegman:その使用パターンは、タスクを返すメソッドとそうでないメソッドの2つのメソッドを提供することによって、より効果的になる可能性があります。しかし、もしあなたがそのインタフェースに悩まされているなら、リンクされた答えのように故意にタスクを破棄する '.Forget()'拡張メソッドが価値があるかもしれません。 Roslynの問題を提起するのは、プロジェクトに全く関与していないので、私はバグの文化を知らない。その意味で私は何が "助け"ているかについての声明を出す資格はありません。 –

関連する問題