Microsoft's tutorial on events展示了如何在触发event之前检查null:
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
{ // Potential Race-condition at this point!
Changed(this, e);
}
}但这将打开一个竞赛条件,如Eric Lippert's blog中所详细描述的,他在其中写道,应该通过本地事件来触发事件,以避免出现竞赛条件:
protected virtual void OnChanged(EventArgs e)
{
ChangedEventHandler temp = Changed; // Local copy of the EventHandler
if (temp != null)
{ // Race condition avoided by local variable.
temp(this, e);
}
}虽然这是可行的,但它使许多错误的开发人员感到困惑,而不把它放在本地范围内的事件中。
来自DailyCoding的另一种解决方案是始终初始化事件,使其具有一个空处理程序,因此不需要进行空检查:
// Set with empty delegate, will never be null
public event ChangedEventHandler Changed = delegate { };
protected virtual void OnChanged(EventArgs e)
{
// Neither Null-check nor local variable is needed; just trigger the event.
Changed(this, e);
}这个很有道理,而且很简单。
然而,由于我在网上很少看到这种技术,我认为一定有原因。
用这样的空委托初始化事件有什么坏处吗?
发布于 2013-11-11 17:50:40
您将看到一个绝对微小的性能问题,但是在更高级的情况下存在问题,例如序列化和反序列化类可能导致您丢失假事件处理程序,以及缺少空检查然后抛出异常。
发布于 2013-11-11 17:49:21
Changed = null,它就会崩溃。发布于 2013-11-11 21:33:27
在Eric Lippert的博客文章中,他说:
还有其他解决此问题的方法;例如,初始化处理程序,使其具有永不删除的空操作。但是执行空检查是标准模式。
但在此之前,他还说:
删除调用站点周围的代码空检查不会减少代码中的争用条件的数量.更糟的是,这样做缩小了在不消除竞争的情况下可以发生竞赛的窗口,从而使竞赛条件更难检测。
这是因为正如他所描述的,这种情况仍有可能发生。
在将委托值推到堆栈和调用堆栈之间.
因此,基本上,如果您使用一个空的处理程序,您会遇到一些性能损失(这似乎是这里的共识)。所以你得到的是可读性,但最重要的是:奇怪的行为会更明显。(我从性能较低的->更容易调用陈旧处理程序的情况下推断出这一点),因此,如果您完全意识到这样的事情可能发生,并且null检查不困扰您,那么就去做吧。或者不要,如果你不想的话。
https://stackoverflow.com/questions/19912626
复制相似问题