views:

87

answers:

2

I have a class with an event:

public event MyEventHandler MyEvent;

Is there any way of getting a handle to the collection of objects (by reflection or otherwise) that are listening to this event?

EDIT - Um, sorry to move the goalposts - I need to be able to do this using reflection bc I have a string value representing the event name, and I need to find the listeners. I can't see an obvious way of accessing the GetInvocationList property using reflection...

Thanks!

+5  A: 
List<object> targets = MyEvent.GetInvocationList().Select(d => d.Target).ToList();

Doing this via reflection will be somewhat obfuscated, if even possible, unfortunately, because this syntax:

public event EventHandler MyEvent;

...

MyEvent(this, EventArgs.Empty);

Is syntactic sugar. What this actually does is:

private EventHandler compilerGeneratedName;

public event EventHandler MyEvent
{
    add { compilerGeneratedName += value; }
    remove { compilerGeneratedName -= value; }
}

...

compilerGeneratedName(this, EventArgs.Empty);

In other words, events have always had the declarative shorthand that properties only recently received. As a result, in order to get at the invocation list you'll have to inspect the private variable, which is named by the compiler (unless, of course, you use the longhand syntax yourself and know the name of the instance variable).

There is no direct way to associate an externally exposed event construct with a backing handler any more than there is a direct way to tie a property to a backing variable: namely because there isn't necessarily a one-to-one relationship. Very likely there is, but as a rule it doesn't have to be that way.

You can try using reflection to inspect the private variables that are of the proper EventHandler<> type on the type that declares the event (note that you'll have to do it at the specific type that declares the event, not on a subclass) and see if you can determine some sort of correlation with the names, but this will be an unreliable solution at best.

Adam Robinson
+! good answer - please could you add in how to do this using reflection, as per my updated question?
Shaul
Note: `GetInvocationList()` can only be called from within the class where the event is defined.
Steve Guidi
@Steve: If you're referring to using the event name directly, then you're correct. This is the same issue that I described, where the event name serves as an "alias" of sorts against the compiler-generated backing delegate when used within the declaring class.
Adam Robinson
A: 

MulticastDelegate.GetInvocationList()

Vitaliy Liptchinsky