在一次代码审查中,我发现了这个(简化后的)代码片段来取消注册一个事件处理程序:
Fire -= new MyDelegate(OnFire);
我原本认为这样并不会注销事件处理程序,因为它创建了一个从未注册过的新委托。但是在查看MSDN文档后,我发现了几个使用这种语法的代码示例。
于是我开始了一个实验:
internal class Program
{
public delegate void MyDelegate(string msg);
public static event MyDelegate Fire;
private static void Main(string[] args)
{
Fire += new MyDelegate(OnFire);
Fire += new MyDelegate(OnFire);
Fire("Hello 1");
Fire -= new MyDelegate(OnFire);
Fire("Hello 2");
Fire -= new MyDelegate(OnFire);
Fire("Hello 3");
}
private static void OnFire(string msg)
{
Console.WriteLine("OnFire: {0}", msg);
}
}
令我惊讶的是,接下来发生了以下情况:
Fire("Hello 1");
产生了两条消息,与预期相符。Fire("Hello 2");
只产生了一条消息!
这使我相信注销new
委托会起作用!Fire("Hello 3");
抛出了一个NullReferenceException
。
通过调试代码,发现在取消注册事件后,Fire
为null
。
我知道对于事件处理程序和委托,编译器在幕后生成了很多代码。但我仍然不明白我的推理有何错误。
我错过了什么?
附加问题:从Fire
为空时没有事件注册的事实中,我得出结论:在触发事件的任何地方都需要检查是否为null
。