イベントをトリガーするときに(マルチスレッドアプリで)競合状態を回避するための一般的な方法は次のとおりです。
EventHandler<EventArgs> temp = SomeEvent;
if (temp != null) temp(e);
"Remember that delegates are immutable and this is why this technique works in theory. However, what a lot of developers don't realize is that this code could be optimized by the compiler to remove the local temp variable entirely. If this happens, this version of the code is identical to the first version, so a NullReferenceException is still possible."
問題(本によると)は、「このコードは、ローカルの一時変数を完全に削除するためにコンパイラーによって最適化される可能性があります。これが発生した場合、このバージョンのコードは最初のバージョンと同一であるため、NullReferenceExceptionが引き続き発生する可能性があります」
C#経由のCLRによると、これはコンパイラにイベントポインタをコピーさせるためのより良い方法です。
virtual void OnNewMail(NewMailEventArgs e)
{
EventHandler<NewMailEventArgs> temp =
Interlocked.CompareExchange(ref NewMail, null, null);
if (temp != null)
temp(this, e);
}
ここで、CompareExchangeは、NewMail参照がnullの場合はnullに変更し、nullでない場合はNewMailを変更しません。つまり、CompareExchangeはNewMailの値をまったく変更しませんが、NewMail内の値をアトミックでスレッドセーフな方法で返します。リヒター、ジェフリー(2010-02-12)。C#経由のCLR(p.265)。OReillyMedia-A.Kindle版。
私は.Net4.0フレームワークを使用していますが、Interlocked.CompareExchangeはイベントへの参照ではなく、場所への参照を想定しているため、これがどのように機能するかわかりません。
本に誤りがあるか、私がそれを誤解したかのどちらかです。誰かがこのメソッドを実装しましたか?または、ここで競合状態を防ぐためのより良い方法がありますか?
アップデート
それは私の間違いでした、反復ロックされたコードは機能します。間違ったキャストを指定しただけですが、Bradley(下記)によると、.net2.0以降のWindowsでは必要ありません。