2013-02-22 4 views
7
private void NotifyFreeChannelsChanged() //1. 
{ 
    if (FreeChannelsChanged != null) 
    { 
     FreeChannelsChanged(this, null); 
    } 
} 

private void NotifyFreeChannelsChanged() //2. 
{ 
    NotifyCollectionChangedEventHandler h = FreeChannelsChanged ; 
    if (h != null) 
     h(this, e); 
} 

これより優れている理由は何ですか。それはちょっとしたチェックです。大きな違いはありません。イベントデリゲートを呼び出す方がよいでしょうか?

+0

http://stackoverflow.com/questions/3668953/raise-event-thread-safely-best-practice?rq=1 –

+1

オプション#2は、暗黙的に型指定された変数を使用します。私はパフォーマンスが問題ではないときにそれを気にしないでください。可読性と保守性を優先します。 – jay

答えて

6

"Better"?まあ、(特定の)競合状態を含んでいない、そうです。 MultiCastDelegate型は不変であり、意味のあるすべての方法で値型セマンティクスを使用します(参照型ですが、this、さらに重要なのはthisを参照)。そのため、最初に割り当ててチェックします。問題は次のとおりです。

// this evaluates to true... 
if(SomeEvent != null) 
{ 
    // ...but before this line executes, the last 
    // subscriber detached, and now SomeEvent is null. Oops. 
    SomeEvent(this, e); 
} 

"なぜ例2を使用しますか?"


さておき、これは暗黙に型付けされた変数(var)を使用するのに最適な場所です。これらの代理人タイプの名前は長くなります...

また、競争状態がまだ存在するということは、それはちょっと微妙です。割り当て後に加入者が削除されるとどうなりますか?さて、それはまだ呼び出されますが、実際にあなたがそれについて行うことができるものは(私が知っている)何もありません。

0

第2の問題は、ヌルチェックとスニペット1でイベントが発生する間にコンテキストスイッチが発生するスレッドバグを防ぐことです。他のスレッドは、その間にヌルに設定できます。

あなたのメソッドがマルチスレッド化されやすいものでなければ、より単純なスニペットを使うことができます。

+0

私は、書いたときにどのようにコードが呼び出されるかとは無関係に、すべて競合状態を避けることを選択しました。それは何の費用もかからない。 –

1

2番目のメソッドは、私たちが使用する拡張メソッドのセットに簡単に対応します。ここでは、EventHandlerがメソッドのターゲットです。

public static void Raise(this EventHandler handler, object sender) 
{ 
    if (handler != null) 
    handler(sender, EventArgs.Empty); 
} 

// And then... 
TheEvent.Raise(this); 

私が知る限り、ハンドラをメソッドに渡すという事実は、競合状態を避けるためにそのローカルコピーを提供します。

関連する問題