7

ほとんどの場合、MVVM を使用するときは、INotifyPropertyChanged インターフェイスを使用してバインディングに通知を提供します。一般的な実装は次のようになります。

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));
        }
    }
}

専門家からコードを読むときはいつでも、これは私にとってはうまくいきます-彼らは同様のコードを書きました:

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));
        }
    }
}

PropertyChanged イベントの一時オブジェクトを作成する正確な理由を知りたいです。

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

Jonの答えと説明された例で答えを見つけました:

C# を理解する: 一時変数を使用してイベントを発生させる

これを理解するためのサンプル コードを次に示します。

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;
      }
}
4

4 に答える 4

25

一時オブジェクトを作成していません。競合状態を回避するためにローカル変数を使用しています。

このコードでは:

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

が無効チェックに (最後のサブスクライバーがサブスクライブを解除したために)PropertyChangedになる可能性があります。nullNullReferenceException

ローカル変数を使用する場合は、null をチェックする参照が、イベントの発生に使用する参照と同じであることを確認してください。したがって、例外は発生しません。サブスクライブを解除したばかりのサブスクライバーに電話をかけることになる可能性があるという点で、まだ競合状態がありますが、これは避けられません。

于 2013-07-02T13:21:33.260 に答える
4

これは、(イベント ハンドラーがアタッチされているかどうかを確認するために) null をチェックしてからイベントを呼び出すまでの間に、最後の (または唯一の) イベント ハンドラーがイベントから削除されるというまれなケースを回避するためです。それが起こった場合、あなたはNullReferenceException.

メモリ リークが心配な場合でも、心配する必要はありません。これは単なる参照であり、イベント ハンドラのコピーではありません。

詳細はこちら

于 2013-07-02T13:22:25.910 に答える
1

これは、スレッド セーフの理由から良い方法です。

元のコードでは、ステートメントの、次の行でイベントが発生する前に、別のスレッドがPropertyChangedハンドラーを削除することが理論的に可能です。これにより、.ifNullReferenceException

2 番目のサンプルは、このリスクを取り除きます。

于 2013-07-02T13:22:48.390 に答える
0

マルチスレッド シナリオを処理する場合にのみ違いが生じます。最後のイベント ハンドラーが!= nullチェック後に登録解除されると、実際の呼び出しでコード 1 の NullReferenceException が発生する可能性があります。

ただし、コード 2 では、デリゲート (イベントの背後にある概念) は不変であり、一時変数の値を変更できないため、この問題はありません。

ただし、ベスト プラクティスとして、常にバリアント 2 を使用することをお勧めします。これにより、将来的に頭痛の種が減る可能性があります ;-)

于 2013-07-02T13:22:30.183 に答える