我有一个数据结构类,它是更大的数据/状态类的子代。
内部数据结构在包含的数据发生更改时触发事件。此事件由较大的数据/状态类使用。然后,数据/状态类将触发其自己的事件,以便它可以将其他信息传递给下一个事件处理程序。
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。为什么?
---- ---- EDIT 我知道检查Null会阻止异常。混淆是为什么这个事件首先是空的= D
答案 0 :(得分:3)
您应始终使用以下模式引发事件以避免空引用和线程问题:
private void DataCountChanged(object sender, EventArgs e)
{
var dr = DataRemoved;
if (dr != null)
{
dr(this, e);
}
}
处理程序为null的原因是它应该被视为一个特殊的委托集合。当集合为空时,委托具有空值。当您附加一个或多个处理程序时,该集合不再为空,因此不再为空。
答案 1 :(得分:0)
if(DataRemoved != null && DataRemoved.GetInvocationList().Length > 0)
{
}
答案 2 :(得分:0)
为您的活动分配空委托可能不是一个好的设计实践。事件本质上是委托,就像函数指针一样。换句话说,它们就像你班上的其他参考成员一样。除非您为它们分配值或订阅它们,否则它们将是且应该为空。
您获得的空引用异常与声明private MyClass;
的原因相同,然后在为其分配值之前尝试使用它。
当您订阅某个活动时,您实际上是在告诉该活动要调用哪个功能。如果您的事件没有至少一个这样的函数指针,它将不存在(NULL)。
答案 3 :(得分:-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,但实际发生的是,您将null赋给事件使用的私有委托。