TheFaithfulLearner
TheFaithfulLearner

Reputation: 693

Subscribe to event from reflection with generic parameters

Alright, so I want to subscribe to an event, using reflection, which has generic parameters.

I also want to just make sure I've got the terminology right when I say 'subscribe to an event'. I mean something like this:

Mediator.EventMediator.Instance.PopulateItemsEvent += (sender, args) =>
        {
}

And I want to get ahead of some of you on this one: there are similar questions out there on Stackoverflow and I have read all the ones I could find. Most relate to events without generic parameters or methods with generic parameters.

So, I have a variable called 'o' which is itself a reflected property which is an ObservableCollection. And it's from 'o' that I want to get the event (specifically, 'CollectionChanged'). But this is what I don't know how to do.

To get 'o', I have used reflection as follows:

var o = propertyInfo.GetValue(this, null);

The first suggestion I tried was 'GetRaisedMethod', which is a property of EventInfo.

So to get the EventInfo, I used the following code:

EventInfo evi = o.GetType().GetEvent("CollectionChanged", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

'evi' does seem to contain the correct information, but then if I use this line:

var invocation = evi.GetRaiseMethod();

I get null. But I already read about that in the questions I have already browsed and it seems this is very common. Even still, I thought I should try it.

Then I went on to another way which was presented in a different question to see if that worked. This is as follows:

var field = typeof(ObservableCollection<>).GetField("CollectionChanged", BindingFlags.NonPublic | BindingFlags.Instance);
var eventDelegate = field.GetValue(o) as MulticastDelegate;

Now this caused an exception for me which I narrowed down to the second of those two lines. The message was as follows:

"Late bound operations cannot be performed on fields with types for which Type.ContainsGenericParameters is true."

And so this is where I figured this was an event with generic parameters. But I've not been able to find anywhere that solves this. Certainly for a method, you can use MethodInfo.MakeGenericMethod(), but there is no such thing in EventInfo.

All I want is to be able to subscribe to that event like normal, but so far it's eluding me.

You might also think I can just do something like this:

(o as ObservableCollection<>).CollectionChanged +=...

But I can't. I've tried all manner of variations of the above (without angular brackets, with, with my own type (of type Type, which is the type of the item in the collection). None worked for me. Surely it would be simpler, but I've not hit upon a way with this approach.

Upvotes: 0

Views: 622

Answers (1)

thehennyy
thehennyy

Reputation: 4218

The EventInfo.AddEventHandler method can do the work for you, have a look at this example:

public static void Main()
{
    var collection = new ObservableCollection<string>(new [] { "a", "b" });
    var o = (object)collection;

    var eventInfo = o.GetType().GetEvent("CollectionChanged");
    var myEventHandler = new Action<object, NotifyCollectionChangedEventArgs>(( s, a ) => Console.WriteLine(a));
    var del = Delegate.CreateDelegate(eventInfo.EventHandlerType, myEventHandler.Method);

    eventInfo.AddEventHandler(o, del);

    collection.Add( "x" );
}

Upvotes: 1

Related Questions