views:

411

answers:

4

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 ?

A: 

assuming a pub/sub environment, just call provider.Unsubscribe(EventType,subscriber) and let the provider determine whether the subscriber is subscribed or not

Steven A. Lowe
+3  A: 

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.

Doug L.
While your post is accurate, he wants to check if he has already assigned a *specific* handler to the event, not if ANY handler is assign (i.e. it's not null).
Noon Silk
Yeah, Silky is right. I want to know whether handler is already attached or not.
Amit
+1  A: 

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)
    {

    }
}`
Chris Richner
When we register for an event, every time we instatiate a new Delegate instance so i wont be having the delegate to get the invocation list. Isn't it ?
Amit
We don't query the delegate instance itself but the Target property on it.We like to know if Class A has registered an event handler to our event ( multicast delegate), so we query all registered delegates on our event to look for a delegate that has our Class A instance in the Target property, hope this helps
Chris Richner
Yeah, thats what is needed :)But again how we can achieve this ???
Amit
Did it serve your needs?
Chris Richner
A: 

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.

Lasse V. Karlsen