12

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;

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

ここで明らかな何かが欠けていますか?

4

5 に答える 5

18

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

于 2009-10-22T19:32:50.407 に答える
5

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

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

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

于 2009-10-22T19:32:41.343 に答える
3

これについては、 Eric Lippertが非常に詳細な記事で既に説明しています。

于 2009-10-22T19:34:56.540 に答える
1

これもMSDNからです..

「デリゲートの呼び出しリストは、リストの各要素がデリゲートによって表されるメソッドの 1 つを正確に呼び出すデリゲートの順序付けられたセットです。呼び出しリストには、重複したメソッドを含めることができます。呼び出し中、メソッドは次の順序で呼び出されます。デリゲートは、呼び出しリストにあるすべてのメソッドを呼び出そうとします. 呼び出しリストに表示されるたびに、重複したメソッドが呼び出されます. デリゲートは不変です. 一度作成されると、デリゲートの呼び出しリストは変更されません. . "

于 2009-10-22T19:41:21.503 に答える
0

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

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

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

于 2009-10-22T19:41:28.550 に答える