Search code examples
c#eventsdelegateseventhandler

Check if a method is already registered to an event


I am trying to properly check if an object's event has already been set to a specific method.

That stackoverflow question offers 2 solutions :

  • a quick and dirty one which simply unregisters the method and registers it again.
  • a more proper one which checks if the delegate to the method has been added.

I have several questions related to the second solution. Let's assume the following code

public static class Util
{
    public static bool IsRegistered<T>(this EventHandler<T> handler, Delegate prospectiveHandler) 
        => handler != null
        && handler.GetInvocationList().Any(existingHandler => existingHandler == prospectiveHandler));
}

public class Object1 
{
    public event EventHandler<string> OnSomething;

    public bool CheckOnSomething(Delegate handler) => this.OnSomething.IsRegistered(handler);
}

public class Object2
{
    private Object1 o;
    public Object2(Object1 o1)
    {
        this.o = o1;
    }

    public void CatchSomething(object sender, string something)
    {
        // ...
    }

    public void HookToSomething()
    {
        if (!o.CheckOnSomething( ??? ))
            o.OnSomething += this.CatchSomething;
    }
}
  1. In order to call CheckOnSomething, i need to pass a delegate to CatchSomething. Do i have to define a new delegate for that, or is there already something i can use ?
  2. If i define a new delegate, will the delegate equality work ? The documentation says it checks for the delegate type, but since i pass the method directly, isn't a new delegate type created on the fly, which would make the equality always return false ?

Solution

  • In order to call CheckOnSomething, I need to pass a delegate to CatchSomething. Do I have to define a new delegate for that, or is there already something I can use ?

    You could pass CatchSomething directly:

    if (!o.CheckOnSomething(CatchSomething))
        o.OnSomething += CatchSomething;
    

    But you would need to update CheckOnSomething to accept a specific delegate type, so that CatchSomething can be converted:

    public bool CheckOnSomething(Action<object, string> handler)
        => this.OnSomething.IsRegistered(handler);
    

    This improves type-safety also, because only delegates with the correct signature can now be passed.

    If I define a new delegate, will the delegate equality work ? The documentation says it checks for the delegate type, but since I pass the method directly, isn't a new delegate type created on the fly, which would make the equality always return false ?

    Passing the method creates a new delegate instance not a new delegate type; the delegate type will always be Action<object, string>.

    However, delegate equality relies on target as well as type, so passing CatchSomething will only be considered equal if it is form the same instance.

    For example:

    var obj1 = new Object1();
    var instance1 = new Object2(obj1);
    
    // Creates a delegate instance:
    Action<object, string> catchSomething = instance1.CatchSomething;
    
    catchSomething == instance1.CatchSomething; // true
    
    var instance2 = new Object2(obj1);
    
    catchSomething == instance2.CatchSomething; // false