没有听众的事件会对性能产生相当大的影响吗?

Erw*_*yer 3 .net c# events

考虑以下基类中与事件相关的基本代码:

public event EventHandler Updated;

public void OnUpdated() {
    if (Updated != null) Updated(sender: this, e: null)
}
Run Code Online (Sandbox Code Playgroud)

如果没有人订阅了更新的事件,我不希望第四行导致任何重大的性能拖累(想法是让订阅者选择要订阅的最细粒度的事件,只发起最少数量的事件并防止消息队列超载).

我应该关心并跟踪订户的存在(例如,使用if (Updated != null && OnUpdateSubscribed) Updated(sender: this, e: null)或信任编译器/运行时?

Mar*_*ell 8

该检查OnUpdate != null 定义了正在订阅/取消订阅的事件.实际上,布尔检查和空检查之间没有真正的区别,因为它们最终都只是一个"加载字段","如果为false则分支" - 因为就逻辑检查而言,空引用计为"假"担心.

我唯一的建议是:将它存储在局部变量中,以防止(非常不可能,但可能)竞争条件:

var snapshot = Updated;
if(snapshot != null) snapshot(this, EventArgs.Empty);
Run Code Online (Sandbox Code Playgroud)

所以:不,基本上:没有这个的开销.

例:

public event EventHandler SomeEvent;
protected virtual void OnSomeEvent()
{
    var snapshot = SomeEvent;
    if (snapshot != null) snapshot(this, EventArgs.Empty);
}
Run Code Online (Sandbox Code Playgroud)

编译成(评论是我的):

.method family hidebysig newslot virtual instance void OnSomeEvent() cil managed
{
    .maxstack 3
    .locals init (
        [0] class [mscorlib]System.EventHandler snapshot)

    // var snapshot = SomeEvent
    L_0000: ldarg.0 
    L_0001: ldfld class [mscorlib]System.EventHandler Foo::SomeEvent
    L_0006: stloc.0

    // if(snapshot == null) goto L_0016;
    L_0007: ldloc.0 
    L_0008: brfalse.s L_0016

    // snapshot(this, EventArgs.Empty);
    L_000a: ldloc.0 
    L_000b: ldarg.0 
    L_000c: ldsfld class [mscorlib]System.EventArgs [mscorlib]System.EventArgs::Empty
    L_0011: callvirt instance void [mscorlib]System.EventHandler::Invoke(object, class [mscorlib]System.EventArgs)

    // L_0016: return;
    L_0016: ret 
}
Run Code Online (Sandbox Code Playgroud)