在“ null”上调用扩展方法引用(即没有订阅者的事件)邪恶?
-
05-07-2019 - |
题
邪恶与否?
public static void Raise(this EventHandler handler, object sender, EventArgs args)
{
if (handler != null)
{
handler(sender, args);
}
}
// Usage:
MyButtonClicked.Raise(this, EventArgs.Empty);
// This works too! Evil?
EventHandler handler = null;
handler.Raise(this, EVentArgs.Empty);
请注意,由于扩展方法的性质,如果MyButtonClicked为null,MyButtonClicked.Raise将不会抛出NullReferenceException。 (例如,MyButtonClicked事件没有听众)。
邪恶与否?
解决方案
不是邪恶的。我希望事件默认以这种方式工作。有人可以解释为什么没有订阅者的事件是空的吗?
其他提示
您可以随时声明您的活动(不是我推荐的):
public event EventHandler<EventArgs> OnClicked = delegate { };
这样,当你调用它们时,它们会分配给它们,所以它们不会抛出空指针异常。
您可以在C#3.0中删除委托关键字...
不要忘记使用 [MethodImpl(MethodImplOptions.NoInlining)]
,否则它可能不是线程安全的。
(在很久以前的某个地方读过,记得它,谷歌搜索并找到 http://blog.quantumbitdesigns。 com / tag / events / )
来自java背景,这对我来说似乎总是很奇怪。我认为没有人听一个事件是完全有效的。特别是在动态添加和删除侦听器时。
对我来说,这似乎是C#的gottchas之一,当人们不知道/忘记每次都检查null时会导致错误。
隐藏此实现细节似乎是一个很好的计划,因为它无助于每次检查空值的可读性。我敢肯定,如果没有人在监听,MSFT会说没有构建事件可以获得性能提升,但是在大多数业务代码中,无意义的空指针异常/可读性的降低大大超过了它。
我还将这两个方法添加到类中:
public static void Raise(this EventHandler handler, object sender)
{
Raise(handler, sender, EventArgs.Empty);
}
public static void Raise<TA>(this EventHandler<TA> handler, object sender, TA args)
where TA : EventArgs
{
if (handler != null)
{
handler(sender, args);
}
}
为什么会是邪恶的?
它的目的很明确:它引发了MyButtonClicked事件。
它确实增加了一个函数调用开销,但是在.NET中它将被优化掉或者相当快。
这有点微不足道,但它解决了我对C#的最大抱怨。
总的来说,我认为这是一个很棒的主意,并且很可能会偷走它。
我不会说这是邪恶的,但我对你的扩展方法如何适应
感兴趣protected virtual OnSomeEvent(EventArgs e){ }
模式以及它如何通过继承处理可扩展性。是否假定所有子类都将处理事件而不是覆盖方法?
虽然我不会将其描述为 evil ,但它仍然具有负面含义,因为它会增加不必要的开销:
致电
myEvent.Raise(this,new EventArgs());
对象EventArgs在所有情况下都被初始化,即使没有人订阅myEvent。
使用时
if (myEvent!= null) {
myEvent(this, new EventArgs());
}
仅当有人订阅了myEvent时才会初始化EventArgs。
当没有处理程序时抛出异常并不是最好的。如果它没有处理程序,最好是空而不是null。