C#中的提升活动:性能与优雅

C#中的提升活动:性能与优雅,c#,.net,events,delegates,lambda,C#,.net,Events,Delegates,Lambda,由于习惯了VB.NET,我习惯于“只引发事件”。当然,自定义事件有所不同,但对于“常规”事件,我不需要在引发之前检查委托是否为Nothing 有了C#,我发现自己在重复这个模式: if (myHandler != null) { myHandler(this, new EventArgs()); } 我在想,以下模式可能会更优雅: myHandler是用空lambda初始化的:myHandler=(sender,e)=>{} myHandler预计永远不会为null,因此提升将变为:

由于习惯了VB.NET,我习惯于“只引发事件”。当然,自定义事件有所不同,但对于“常规”事件,我不需要在引发之前检查委托是否为
Nothing

有了C#,我发现自己在重复这个模式:

if (myHandler != null) 
{
    myHandler(this, new EventArgs());
}
我在想,以下模式可能会更优雅:

  • myHandler是用空lambda初始化的:
    myHandler=(sender,e)=>{}
  • myHandler预计永远不会为null,因此提升将变为:
    myHandler(这是新的EventArgs())
  • 这种模式的性能会比前一种模式高还是低?
    是否有其他重要的考虑因素?

    < P>不认为在第一和第二之间提供有意义的差异,至少没有考虑它们。在过于频繁地使用委托时,缺少
    if(myHandler!=null)
    会给您带来一些性能优势。因此,如果您确定处理程序永远不会为null,请摆脱该控件,基本上您就完成了。

    这是在构造过程中额外发生的事情,但不会产生巨大的开销。需要注意的一点是,一些序列化框架,如
    DataContractSerializer
    (WCF)不运行构造函数或字段初始值设定项,因此它可能毕竟不是非空的。就个人而言,如果您的大多数事件都是
    EventHandler
    ,我可能会尝试使用扩展方法:

    public static void SafeInvoke(this EventHandler handler, object sender) {
        if (handler != null) handler(sender, EventArgs.Empty);
    }
    
    然后:

    尽管坦率地说,我很少对简单地使用空检查有问题;p


    另一个缺点是,如果您有足够多的事件导致这是一个问题,那么您可能应该改用
    EventHandlerList
    ,而这种方法不适用于
    EventHandlerList

    通常的做法是使用受保护的虚拟方法OnEventName,您可以在其中检查事件是否为null并引发它:

    protected virtual void OnEventName(parameters)
    {
        if (EventName != null)
            EventName(this, new EventNameEventArgs(parameters);
    }
    
    这允许您将所有事件引发代码放在一个位置(无空检查重复),并在以后需要时覆盖它。因此,我不认为在每个事件中添加一个虚拟事件处理程序比在每个事件中进行一个空检查有任何好处


    顺便说一句,添加虚拟处理程序的较短方法是
    myHandler=delegate{}

    我认为这两种方法之间的性能差异不足以产生相关性。如果有什么区别的话,我认为空检查要比通过委托调用方法便宜,即使它是不可操作的

    当谈到优雅时,应该指出VB.NET中的
    RaiseEvent
    关键字与您自己用C#编写的构造完全相同:

    如果希望避免在整个代码中重复该构造,可以将其封装在两个扩展方法中:

    public static void RaiseEvent(this EventHandler source, object sender)
    {
        if (source != null)
        {
            source.Invoke(sender, new EventArgs());
        }
    }
    
    public static void RaiseEvent<T>(this EventHandler<T> source, object sender, T eventArgs)
        where T : EventArgs
    {
        if (source != null)
        {
            source.Invoke(sender, eventArgs);
        }
    }
    

    这在语义上与VB.NET中使用的样式相同。

    请参见此非常类似问题的答案:
    If (Not MyEvent Is Nothing) Then
      MyEvent.Invoke(New EventArgs())
    End If
    
    public static void RaiseEvent(this EventHandler source, object sender)
    {
        if (source != null)
        {
            source.Invoke(sender, new EventArgs());
        }
    }
    
    public static void RaiseEvent<T>(this EventHandler<T> source, object sender, T eventArgs)
        where T : EventArgs
    {
        if (source != null)
        {
            source.Invoke(sender, eventArgs);
        }
    }
    
    myEvent.RaiseEvent(this);
    myOtherEvent.RaiseEvent(this, new SomeEventArgs());