2013-07-02 10 views
7

我々はバインディングに通知を提供するために、INotifyPropertyChangedインターフェイスを使用して、一般的な実装は、このようになりますMVVMを使用するほとんどの時間:なぜイベントを発生させるためにtempraryオブジェクトを使用する必要がありますか?

public class MyClass : INotifyPropertyChanged 
{ 
    // properties implementation with RaisePropertyChanged 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected void RaisePropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

私はからコードを読む時はいつでもこれが私のために正常に動作します私はPropertyChangedイベントのための一時的なオブジェクトを作成するの背後にある正確な理由が何であるかを知っていただきたいと思い

public class MyClass : INotifyPropertyChanged 
{ 
    // properties implementation with RaisePropertyChanged 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected void RaisePropertyChanged(string propertyName) 
    { 
     var tempchanged = PropertyChanged; 
     if (tempchanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

: - 専門家は、彼らが同様のコードを書きました。

それは良い習慣であるか、それに関連するその他の利点はありますか?

でJonの答えと説明した例と答え、私を発見した:

Understanding C#: Raising events using a temporary variable

ここではこれを理解するためのサンプルコードです:

using System; 
using System.Collections.Generic; 
using System.Threading; 

class Plane 
{ 
    public event EventHandler Land; 

    protected void OnLand() 
    { 
      if (null != Land) 
      { 
       Land(this, null); 
      } 
     } 

    public void LandThePlane() 
    { 
      OnLand(); 
     } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
      Plane p = new Plane(); 
      ParameterizedThreadStart start = new ParameterizedThreadStart(Run); 
      Thread thread = new Thread(start); 
      thread.Start(p); 

      while (true) 
      { 
       p.LandThePlane(); 
      } 
     } 

    static void Run(object o) 
    { 
      Plane p = o as Plane; 
      while (p != null) 
      { 
       p.Land += p_Land; 
       p.Land -= p_Land; 
      } 
     } 

    static void p_Land(object sender, EventArgs e) 
    { 
      return; 
     } 
} 
+0

イベント[、トピックのエリックリペットの記事を参照してください http://stackoverflow.com/questions/282653/checking-for-null-before-event-dispatching-thread-safe –

+0

、この記事を参照してくださいRaces](http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx) – Brian

答えて

25

あなたは一時的に作成していませんオブジェクト。競合状態を避けるためにローカル変数を使用しています。このコードで

if (PropertyChanged != null) 
{ 
    PropertyChanged(...); 
} 

PropertyChangedが(原因最後の加入者退会に)あなたがNullReferenceExceptionを得る意味します後のNULLかどうかのチェック、nullになることが可能です。

ローカル変数を使用する場合、無効をチェックする参照がイベントを発生させるために使用する参照と同じであることを確認してください。例外は発生しません。登録解除されたばかりの加入者に電話がかかってしまうかもしれないという競合状態はまだありますが、それはやむを得ないことです。

+1

ありがとうJon。これは、状態を理解するのが最も簡単です。 – JSJ

4

null(イベントハンドラが接続されているかどうかを確認するための時間)とイベントを呼び出す時刻との間に、最後のイベントハンドラがイベントから削除されることはまれではありません。それが起きた場合はNullReferenceExceptionになります。

メモリリークが懸念される場合、それは単なるリファレンスであり、イベントハンドラのコピーではありません。最後のイベント・ハンドラが!= null確認後、登録解除された場合、実際の呼び出しは、コード1とNullReferenceExceptionに遭遇するかもしれません:

詳細はhere

0

それが唯一のマルチスレッドのシナリオを扱う違いを見つけることができます

しかし、コード2にはこの問題はありません。イベントの背後にある概念である代理人は不変であり、したがって一時変数の値は変更できません。

しかし、私は、ベストプラクティスとしてバリアント2一緒に行く常に推薦する - これはあなたの将来の頭痛の種を救うかもしれない;-)

1

をこれは、スレッドの安全性の理由のために良い方法です。元のコードで

、それは後if文をPropertyChangedハンドラを除去するために、別のスレッドのための理論的には可能であるが、前イベントは、次の行で発生します。これにより、NullReferenceExceptionが発生します。

2番目のサンプルは、このリスクを排除します。

関連する問題