How to correctly unregister an event handler

前端 未结 2 1492
滥情空心
滥情空心 2020-11-29 20:00

In a code review, I stumbled over this (simplified) code fragment to unregister an event handler:

 Fire -= new MyDelegate(OnFire);

I though

2条回答
  •  孤城傲影
    2020-11-29 20:18

    The C# compiler's default implementation of adding an event handler calls Delegate.Combine, while removing an event handler calls Delegate.Remove:

    Fire = (MyDelegate) Delegate.Remove(Fire, new MyDelegate(Program.OnFire));
    

    The Framework's implementation of Delegate.Remove doesn't look at the MyDelegate object itself, but at the method the delegate refers to (Program.OnFire). Thus, it's perfectly safe to create a new MyDelegate object when unsubscribing an existing event handler. Because of this, the C# compiler allows you to use a shorthand syntax (that generates exactly the same code behind the scenes) when adding/removing event handlers: you can omit the new MyDelegate part:

    Fire += OnFire;
    Fire -= OnFire;
    

    When the last delegate is removed from the event handler, Delegate.Remove returns null. As you have found out, it's essential to check the event against null before raising it:

    MyDelegate handler = Fire;
    if (handler != null)
        handler("Hello 3");
    

    It's assigned to a temporary local variable to defend against a possible race condition with unsubscribing event handlers on other threads. (See my blog post for details on the thread safety of assigning the event handler to a local variable.) Another way to defend against this problem is to create an empty delegate that is always subscribed; while this uses a little more memory, the event handler can never be null (and the code can be simpler):

    public static event MyDelegate Fire = delegate { };
    

提交回复
热议问题