这是一个扩展方法的好主意吗?

时间:2011-09-29 03:38:49

标签: c# events extension-methods

我常常看到这样的代码在源代码中分散和重复:

var handler = MyEvent;

if (handler != null)
{
    handler.Invoke(null, e);
}

有没有理由不将它封装在像这样的扩展方法中?

public static void SafeInvoke<T>(this EventHandler<T> theEvent, object sender, T e) where T : EventArgs
{
    var handler = theEvent;

    if (handler != null)
    {
        handler.Invoke(sender, e);
    }
}

这样就可以这样调用:

MyEvent.SafeInvoke(this, new MyEventArgs(myData));

3 个答案:

答案 0 :(得分:3)

这是一个有趣的问题。杰弗里里希特通过C#在 CLR中对此进行了很多讨论。

使用如下所示的空检查: -

var handler = MyEvent;

if (handler != null)
{
    handler.Invoke(null, e);
}

JIT编译器可能完全优化掉handler变量。但是,CLR团队意识到许多开发人员使用此模式来引发事件并将此感知构建到JIT编译器中。这可能会在CLR的所有未来版本中保留,因为更改行为可能会破坏太多现有应用程序。

没有理由你不能写一个扩展方法来为你做这项工作(这正是我所做的)。请注意,方法本身可能是JIT内联(但临时变量仍然不会被优化掉)。

如果您设想将您的应用程序用于其他运行时,例如Mono(我怀疑它反映了CLR在这种情况下的行为)或者可能出现的其他一些奇特的运行时,然后你可以通过在扩展方法中添加[MethodImplAttribute(MethodImplOptions.NoInlining)]来防止你的代码反对JIT内联的可能性。

如果您决定不使用扩展方法,另一种防止JIT优化的方法(Jeffrey Richter建议)是以JIT编译器无法优化的方式将值分配给临时变量,例如< / p>

var handler = Interlocked.CompareExchange(ref MyEvent, null, null);

答案 1 :(得分:0)

可能是因为Performance considerations

答案 2 :(得分:0)

如果模式困扰你,你可以自由地创建这样的扩展方法。

我能看到的唯一缺点是扩展方法类所在的命名空间的依赖性增加,以及其他开发人员需要浪费3到5秒的时间来解决SafeInvoke的问题。