是否在“null”引用(即没有订阅者的事件)上调用扩展方法?

时间:2008-10-29 19:19:44

标签: c# events extension-methods

邪恶与否?

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事件没有听众)。

邪恶与否?

8 个答案:

答案 0 :(得分:35)

不是邪恶的。我希望事件默认以这种方式工作。有人可以解释为什么没有订阅者的事件是空的吗?

答案 1 :(得分:14)

您可以随时声明您的活动(不是我推荐的):

public event EventHandler<EventArgs> OnClicked = delegate { };

这样,当你调用它们时,它们会分配给它们,所以它们不会抛出空指针异常。

您可以在C#3.0中删除委托关键字...

答案 2 :(得分:9)

不要忘记使用[MethodImpl(MethodImplOptions.NoInlining)],否则它可能不是线程安全的。

(很久以前在某地读过,记得它,用Google搜索并发现http://blog.quantumbitdesigns.com/tag/events/

答案 3 :(得分:6)

来自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);
        }
    }

答案 4 :(得分:5)

为什么会是邪恶的?

它的目的很明确:它引发了MyButtonClicked事件。

它确实增加了一个函数调用开销,但是在.NET中它将被优化掉或者相当快。

这有点微不足道,但它解决了我对C#的最大抱怨。

总的来说,我认为这是一个很棒的主意,并且很可能会偷走它。

答案 5 :(得分:0)

我不会说这是邪恶的,但我对你的扩展方法如何适应

感兴趣
protected virtual OnSomeEvent(EventArgs e){ }

模式以及它如何通过继承处理可扩展性。是否假定所有子类都将处理事件而不是覆盖方法?

答案 6 :(得分:0)

虽然我不会将其描述为 evil ,但它仍然具有负面含义,因为它会增加不必要的开销:

致电

myEvent.Raise(this, new EventArgs());

对象EventArgs在所有情况下都被初始化,即使没有人订阅myEvent。

使用时

if (myEvent!= null) {
   myEvent(this, new EventArgs());
}

仅当有人订阅了myEvent时才会初始化EventArgs。

答案 7 :(得分:-2)

当没有处理程序时抛出异常并不是最好的。如果它没有处理程序,最好是空而不是null。