この質問にはすでに答えがあります。
だから私は直接イベントを呼び出すのではなく、それについて読みました
if (SomeEvent != null)
SomeEvent(this, null);
すべきだ
SomeEventHandler temp = SomeEvent;
if (temp != null)
temp(this, null);
これはなぜですか。 2番目のバージョンはどのようにスレッドセーフになりますか?ベストプラクティスは何ですか?
イベントは、実際にはデリゲートのリストに対する構文上の糖です。イベントを呼び出すとき、これは実際にそのリストを反復処理して、渡されたパラメータを使用して各デリゲートを呼び出すことです。
スレッドの問題点は、購読/購読解除によってこのコレクションにアイテムを追加または削除できることです。あなたがコレクションを繰り返している間にそれらがこれをした場合、これは問題を引き起こすでしょう(私は例外が投げられると思います)
その目的は、リストを繰り返す前にリストをコピーすることであるため、リストに対する変更から保護されています。
注:ただし、購読を解除した後もリスナーを起動できるようになったため、リスナーコードでこれを確実に処理するようにしてください。
IMO、他の答えでは、1つの重要な詳細が欠けています。不変。これの重要な点は、イベントハンドラを購読または購読解除することです。しない単にリストに追加/削除するだけです。置き換えます追加の(または1つ少ない)アイテムを含む新しいリストのリスト。
参照はアトミックであるので、これはあなたがする時点でそれが意味する:
var handler = SomeEvent;
あなたは今持っています硬い次のピコ秒で別のスレッドが購読を中止したとしても、変更できないインスタンス(実際のになるイベントフィールドnull
)
ですから、nullをテストしてそれを呼び出すだけで、すべて問題ありません。もちろんありますそれでもイベントの混乱を招くシナリオ上げたピコ秒前に退会したと思われるオブジェクトに!
lock
)地域(古いコンパイラ) - Marc Gravell♦