在代码审查中,我偶然发现了这个(简化的)代码片段来取消注册事件处理程序:
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
触发事件,null
都需要进行检查。