Amit
Amit

Reputation: 1057

How to find out whether somebody has subscribed to an event?

I have a use case where i have to unsubscribe for an event. But prior to unsubscribing i want to make sure whether this guy has actully hooked on to this event or not.

Please let me know how i can achieve this ?

EDIT: Suppose there is a class A which provide an event ABC and other class B has registered for this event. Now somewhere in a method i need to do the Unsubscription for B. But before unsubscribing i want to make sure whether this guy has really subsribed to this event. Now how i could do this ?

Upvotes: 3

Views: 4364

Answers (3)

Chris Richner
Chris Richner

Reputation: 2883

The sample class Publisher provides one event Publish. The method IsRegistered queries the events attached event handlers for the given class instance and returns true if there is at least one registered / attached event handler by this class instance. The overriden IsRegistered method does the same but for static types.

Put this code into a console application project and hit F5 to debug, give it a try.

internal class Publisher
{
    internal event EventHandler<EventArgs> Publish;

    internal bool IsRegistered(Type type)
    {
        if (Publish == null) return false;
        //
        return (from item in Publish.GetInvocationList() where item.Target == null & item.Method.DeclaringType == type select item).Count() > 0;

    }
    internal bool IsRegistered(object instance)
    {
        if (Publish == null) return false;
        //
        return (from item in Publish.GetInvocationList() where item.Target == instance select item).Count() > 0;
    }

    static int Main(string[] args)
    {
        Publisher p = new Publisher();
        //
        p.Publish += new EventHandler<EventArgs>(static_Publish);
        p.Publish += new EventHandler<EventArgs>(p.instance_Publish);            
        //
        Console.WriteLine("eventhandler static_Publish attach: {0}", p.IsRegistered(typeof(Program)));
        Console.WriteLine("eventhandler instance_Publish attach: {0}", p.IsRegistered(program));
        //
        return 0;
    }

    void instance_Publish(object sender, EventArgs e)
    {

    }
    static void static_Publish(object sender, EventArgs e)
    {

    }
}`

Upvotes: 1

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391326

There are two ways you can do this:

  1. You can create a new delegate chain, with the delegate that is unsubscribing removed, and compare to the one you got before you save it. In the case where you're unsubscribing a delegate that has subscribed, you will get back a new delegate chain, without that delegate. In the case where you're trying to unsubscribe a delegate that has not subscribed, you will get back the same chain as the one you had.
  2. You can manually walk the delegate chain to see if the delegate you want to unsubscribe is present. This can be done using the normal Linq methods like .Contains for simplicity.

The first case can look like the code below. This will create a new delegate chain in a temporary variable, with the delegate you want to removed, removed, and then compare the temp chain to the existing chain. If they're the same, the delegate was not present.

private EventHandler _Changed;
public event EventHandler Changed
{
    add
    {
        _Changed += value;
    }
    remove
    {
        EventHandler temp = _Changed - value;
        if (_Changed == null || temp == _Changed)
            throw new InvalidOperationException(
                "Delegate is not subscribed, cannot unsubscribe");
        _Changed = temp;
    }
}

The second like the code below, this will simply see if the delegate you want to unsubscribe is present in the chain of delegates.

private EventHandler _Changed;
public event EventHandler Changed
{
    add
    {
        _Changed += value;
    }

    remove
    {
        if (_Changed == null || !_Changed.GetInvocationList().Contains(value))
            throw new InvalidOperationException(
                "Delegate is not subscribed, cannot unsubscribe");
        _Changed -= value;
    }
}

Note that you could, if you want, use similar code to handle the case where a delegate is being added twice.

Upvotes: 0

Doug L.
Doug L.

Reputation: 2716

From Microsoft:

        // Wrap event invocations inside a protected virtual method
        // to allow derived classes to override the event invocation behavior
        protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<CustomEventArgs> handler = RaiseCustomEvent;

            // Event will be null if there are no subscribers
            if (handler != null)
            {
                // Format the string to send inside the CustomEventArgs parameter
                e.Message += String.Format(" at {0}", DateTime.Now.ToString());

                // Use the () operator to raise the event.
                handler(this, e);
            }
        }

You're looking for the if (handler != null) part. It's null if there are not any subscribers, not null if there are subscribers.

Upvotes: 3

Related Questions