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;

最后,第二个事件应该由另一个事件处理程序处理以完成一些工作。不幸的是,触发第二个事件的调用通常会因 NullReferenceException 而失败。为什么?

----编辑---- 我知道检查 Null 将防止异常。令人困惑的是为什么这个事件首先是 Null =D

4

4 回答 4

3

您应该始终使用以下模式引发事件,以避免空引用和线程问题:

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

处理程序为空的原因是它应该被视为一个特殊的委托集合。当集合为空时,委托具有空值。当您附加一个或多个处理程序时,集合不再为空,因此不再为空。

于 2012-04-27T02:26:06.503 回答
0
if(DataRemoved != null && DataRemoved.GetInvocationList().Length > 0)
            {
            }
于 2012-04-27T01:33:40.733 回答
0

为您的事件分配一个空委托可能不是一个很好的设计实践。事件本质上是类似于函数指针的委托。换句话说,它们就像您班级中的其他参考成员一样。除非您为它们分配一个值或订阅它们,否则它们将为并且应该为空。

private MyClass;您获得的空引用异常与声明然后尝试在分配值之前使用它的原因相同。

当您订阅一个事件时,您实际上是在告诉事件要调用哪个函数。如果您的事件没有至少一个这样的函数指针,它就不会存在(NULL)。

于 2012-04-27T02:36:13.383 回答
-3

有一个技巧可以避免空检查:

只需按如下方式初始化您的事件:

public event YourDelegate MyEvent = delegate { };

这样您就不需要检查空值,只需像往常一样调用事件:

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 使用的私有委托

资料来源:Jon Skeet,C# 深度分析,事件

于 2012-04-27T00:46:30.270 回答