web-dev-qa-db-ja.com

ReSharper / C#の「デリゲート減算は予測できない結果をもたらしますか?」

myDelegate -= eventHandler ReSharper(バージョン6)の問題を使用する場合:

デリゲート減算には予測不可能な結果があります

この背後にある理性は ここでJetBrainsによって説明される です。説明は理にかなっており、それを読んだ後、デリゲートでの-の使用を疑っています。

それでは

  • reSharperを不機嫌にせずに非自動イベントを書くことはできますか?
  • または、これを実装するより良いおよび/または「正しい」方法がありますか?
  • または、ReSharperを無視してもいいですか?

簡略化されたコードは次のとおりです。

public delegate void MyHandler (object sender);

MyHandler _myEvent;

public event MyHandler MyEvent
{
    add
    {
        _myEvent += value;
        DoSomethingElse();
    }
    remove
    {
        _myEvent -= value; // <-- ReSharper warning here
    }
}
117
user166390

恐れるな! ReSharperの警告の最初の部分は、デリゲートのリストの削除にのみ適用されます。コードでは、常に1つのデリゲートを削除しています。第2部では、重複したデリゲートが削除された後のデリゲートの順序について説明します。イベントは、そのサブスクライバーの実行順序を保証するものではないため、実際にはユーザーにも影響しません。

上記のメカニズムは予測できない結果をもたらす可能性があるため、ReSharperはデリゲート減算演算子に遭遇するたびに警告を発行します。

ReSharperはこの警告を発行しています。これは、マルチキャストデリゲートの減算が問題になる可能性があり、その言語機能を完全に非難していないためです。幸いなことに、これらの落とし穴はフリンジケースにあり、単純なイベントをインスツルメントしているだけではそれらに遭遇することはほとんどありません。独自のadd/removeハンドラーを実装するより良い方法はありません。注意してください。

そのメッセージに対するReSharperの警告レベルを「ヒント」にダウングレードすることをお勧めします。そうすることで、通常は有用な警告に鈍感になりません。

127
Allon Guralnek

デリゲートを直接使用して合計または減算しないでください。代わりにあなたのフィールド

MyHandler _myEvent;

代わりにイベントとしても宣言する必要があります。これにより、ソリューションを危険にさらすことなく問題を解決できますが、イベントを使用する利点があります。

event MyHandler _myEvent;

デリゲートの合計または減算の使用は、単にデリゲートを割り当てるとイベントが失われる可能性があるため、危険です(宣言により、開発者は、イベントとして宣言されたときに、これがマルチキャストデリゲートであると直接推論しません)。単に例として、この質問に記載されているプロパティにイベントとしてフラグが付けられていない場合、次のコードは、誰かが単にデリゲートに割り当てられているため、最初の2つの割り当てがLOSTであることを示します(これも有効です!)。

myObject.MyEvent += Method1; 
myObject.MyEvent += Method2;
myObject.MyEvent = Method3;

Method3を割り当てると、2つの初期サブスクリプションが完全に失われました。イベントを使用すると、この問題が回避され、同時にReSharper警告が削除されます。

17
blimac