0

より大きなデータ/状態クラスの子であるデータ構造クラスがあります。

内部データ構造は、含まれているデータが変更されたときにイベントを発生させます。このイベントは、より大きなデータ/状態クラスによって消費されます。データ/状態クラスは、次のイベント ハンドラーに追加情報を渡すことができるように、独自のイベントを発生させます。

Public class Data
{
    //properties and objects go here

    public int Count
    {
        get { return _count; }
        internal set 
        {
            //if the count grew simply set _count
            if (value != _oldCount)
            {
                _oldCount = _count;
                _count = value;
            }
            //if the count shrank then set the count and trigger an event if the count is under 100
            else
            {
                _oldCount = _count;
                _count = value;
                if (_count < 100)
                {
                    CountChanged(this, new EventArgs());
                }
            }
        }
    }
    public event EventHandler CountChanged;
}

上記のイベントは、このイベント ハンドラーによって消費されます

Data.CountChanged += new EventHandler(DataCountChanged);
private void DataCountChanged(object sender, EventArgs e)
{
    DataRemoved(this, e);  //Handle the old event and trigger a new event to pass along more information
}
public event EventHandler DataRemoved;

最後に、2 番目のイベントを別のイベント ハンドラーで処理して、何らかの作業を行う必要があります。残念ながら、2 番目のイベントをトリガーする呼び出しは、多くの場合、NullReferenceException で失敗します。なんで?

----編集---- Null をチェックすると例外が防止されることを理解しています。そもそもこのイベントが Null である理由は混乱です = D

4

4 に答える 4

3

null 参照とスレッド化の問題を回避するために、常に次のパターンを使用してイベントを発生させる必要があります。

private void DataCountChanged(object sender, EventArgs e)
{
    var dr = DataRemoved;
    if (dr != null)
    {
        dr(this, e);
    }
}

ハンドラーが null である理由は、デリゲートの特別なコレクションとして表示する必要があるためです。コレクションが空の場合、デリゲートは null 値を持ちます。1 つ以上のハンドラーをアタッチすると、コレクションは空ではなくなるため、null ではなくなります。

于 2012-04-27T02:26:06.503 に答える
0

イベントに空のデリゲートを割り当てることは、適切な設計方法ではない場合があります。イベントは本質的に、関数ポインターのようなデリゲートです。つまり、クラス内の他の参照メンバーと同じです。それらに値を割り当てたり、サブスクライブしたりしない限り、それらは null になり、null になるはずです。

private MyClass;取得する null 参照例外は、値が割り当てられる前に宣言してから使用しようとするのと同じ理由によるものです。

イベントをサブスクライブすると、基本的にどの関数を呼び出すかをイベントに伝えます。イベントにそのような関数ポインターが少なくとも 1 つ含まれていない場合、そのイベントは存在しません (NULL)。

于 2012-04-27T02:36:13.383 に答える
0
if(DataRemoved != null && DataRemoved.GetInvocationList().Length > 0)
            {
            }
于 2012-04-27T01:33:40.733 に答える
-3

null チェックを回避するためのトリックがあります。

次のようにイベントを初期化するだけです。

public event YourDelegate MyEvent = delegate { };

この方法では、null をチェックする必要はなく、通常どおりイベントを呼び出すだけです。

this.MyEvent("Hi there!");

編集済み

明確にするために:

次のようなイベントを宣言します。

public event Action MyEvent;

次のように自動的に変換されます。

private Action myEvent;
public event Action MyEvent
{
   add
   {
      this.myEvent += value;
   }
   remove
   {
      this.myEvent -= value;
   }
}

したがって、次のようなイベントを初期化します。

public event Action MyEvent = delegate { };

外部コードはイベント自体に null を割り当てることができないため、安全です。

ただし、宣言されたクラス内のイベントに null を割り当てることはできますが、実際に起こっていることは、 event によって使用されるプライベートデリゲートに null を割り当てているということです

出典: Jon Skeet、C# の詳細、イベント

于 2012-04-27T00:46:30.270 に答える