質問

MSDNのイベントのページを読んでいただけで、困惑させているサンプルコードのスニペットに出会いました。

問題のコードはこれです:

// Make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler<CustomEventArgs> handler = RaiseCustomEvent;

コードの意図は理解していますが、その特定の行が何かのコピーをどのように作成しているかはわかりません。それがしているのは、参照をコピーすることです。実際には、デリゲートインスタンスのディープコピーは作成していません。そのため、実際には競合状態をまったく防止しません。

ここで明らかな何かを見逃していますか?

役に立ちましたか?

解決

デリゲートは不変であるため、そのコードで取得された参照は変更されないことが保証されています。ユーザーがnullチェックの後にサブスクライブまたはサブスクライブ解除すると、新しいデリゲートが作成され、イベントに設定されます。ただし、完全に異なるオブジェクトへの参照があり、それを呼び出すため、nullになることを心配する必要はありません。

他のヒント

あなたは正しいです。参照をコピーしています。

ただし、デリゲートは不変です。ハンドラーをイベントに追加すると、現在のハンドラーと新しいハンドラーを組み合わせて新しいデリゲートが作成され、フィールドに割り当てられます。

フィールドが参照しているデリゲートインスタンスは変更できないため、競合状態を回避します。

Eric Lippert は、非常に詳細な投稿

これもMSDNからです。

&quot;デリゲートの呼び出しリストは、リストの各要素がデリゲートによって表されるメソッドの1つを呼び出すデリゲートの順序付きセットです。呼び出しリストには、重複するメソッドを含めることができます。呼び出し中、メソッドは呼び出しリストに表示される順序で呼び出されます。デリゲートは、呼び出しリスト内のすべてのメソッドを呼び出そうとします。 重複は、呼び出しリストに表示されるたびに1回呼び出されます。 デリゲートは不変です。作成されたデリゲートの呼び出しリストは変更されません。&quot;

if(whatever!= null)whatever(); は、 whatever()が呼び出されたときに whatever がnullにならないようにします、しかし、スレッド化されたシナリオでは実際にそれを保証しません。別のスレッドは、チェックと呼び出しの間に whatever = null を設定できます。

Foo temp = whatever;
if (temp != null) temp();

temp はローカルであり、したがって別のスレッドによって変更されることはないため、このコードはnull参照解除の可能性を取り除きます。そのため、競合状態を防ぎます。ただし、関連するすべての競合状態を防ぐことはできません。 Eric Lippertはコードに関する他のいくつかの問題について詳しく説明します

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top