3

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 ?
cboittin
  • 161
  • 9
  • Usually you won´t call an event-handler yourself, but just raise the event that will call the handler. So you shouldn´t call `o.CheckSomething` within your `HookToSomething`-method at all. Just use `o.OnSomething += this.CatchSomething` and you´re done. – MakePeaceGreatAgain Feb 26 '21 at 09:47
  • @HimBromBeere But that may assign the same delegate multiple times, if `HookToSomething` is called more than once. – Johnathan Barclay Feb 26 '21 at 09:57
  • @HimBromBeere There is a risk that the event will be registered -- and fired -- multiple times if HookToSomething method is called more than once. – cboittin Feb 26 '21 at 09:58

1 Answers1

3

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
Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35
  • Thanks for your answer. I cannot pass `CatchSomething` directly, the compiler complains that it cannot convert from 'method group' to 'Delegate'. If i undertand you correctly, when i call `o.OnSomething += this.CatchSomething;` the InvocationList for `OnSomething` gets populated with a delegate instance of type `Action` ? – cboittin Feb 26 '21 at 10:09
  • Ah ok, its because you are using `Delegate` rather than a specific delegate type. Try `public bool CheckOnSomething(Action handler)` instead to match the signature of `CatchSomething` (and also `OnSomething`). – Johnathan Barclay Feb 26 '21 at 10:23