为什么“公共事件 EventHandler cccc”为空?
我有一堂课
public class Builder
{
public event EventHandler StartedWorking;
public Builder()
{
// Constructor does some stuff
}
public void Start()
{
StartedWorking(this, eventargobject); //StartedWorking is null --
}
}
这看起来很简单,而且是我一直在做的事情?我是否遗漏了一些明显的东西,或者是否有什么东西可能导致这种情况?
编辑:
这是否意味着,如果我触发一个未在客户端类中订阅的事件,我必须检查它是否不为空?
编辑2:
我想我从来没有遇到过没有订阅的事件,因此从来没有遇到过这种情况—— 你每天学习新的东西 抱歉这个看似愚蠢的问题......
除非有人订阅了该事件,否则事件处理程序将为空。一旦委托订阅了事件,它就不再为空。
这就是为什么总是建议使用以下形式来引发事件:
public void Start()
{
var handler = this.StartedWorking;
if (handler != null)
{
handler(this, eventArgObject);
}
}
如果没有订阅者,这可以保护您免受空异常的影响。
正如其他人已经说过的,它是空的,因为没有订阅者。
回答您的编辑:是的,您应该始终在触发事件之前检查事件是否为空。但是,如果您只是执行简单的
if(StartedWorking != null){...}
操作,则会面临竞争条件的风险,因为订阅者可能会在空检查之后但在触发事件之前取消订阅。因此,在检查事件是否为空时,您应该始终使用此模式:
protected void OnStartedWorking()
{
EventHandler localEvent = StartedWorking
if(localEvent != null)
{
localEvent(this, EventArgs.Empty);
}
}
这可以通过首先获取事件的副本来防止竞争条件,以便订阅列表在复制时固定。
MSDN 上有关于发布事件的更多信息:如何发布符合 .NET Framework 指南的事件
(这有效,因为在 .net 中 MultiCastDelegate 类是不可变的,因此任何更改事件订阅者列表的尝试都不会影响您所做的副本)
不需要分配功能吗?
StartedWorking += new EventHandler(afunction);
void afunction(object sender, EventArgs e)
{
DoSomething();
}
接受的答案是正确的,但从 c# 6.0 开始,有一个称为 空条件运算符 的功能。有了这个功能,通话就可以简化为
public void Start()
{
var handler = this.StartedWorking;
if (handler != null)
{
handler(this, eventArgObject);
}
}
到
public void Start()
{
var handler = this.StartedWorking;
handler?.Invoke(this, eventArgObject);
}
.
这会产生更清晰的代码,并且与接受的答案具有完全相同的行为。