Подписаться на событие из отражения с общими параметрами - PullRequest
0 голосов
/ 03 ноября 2018

Хорошо, поэтому я хочу подписаться на событие, используя отражение, которое имеет общие параметры.

Я также хочу просто убедиться, что я правильно понял терминологию, когда говорю «подписаться на событие». Я имею в виду что-то вроде этого:

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

И я хочу опередить некоторых из вас в этом вопросе: на Stackoverflow есть похожие вопросы, и я прочитал все, что смог найти. Большинство из них относятся к событиям без общих параметров или методов с общими параметрами.

Итак, у меня есть переменная с именем 'o', которая сама является отраженным свойством и представляет собой ObservableCollection. И именно от «о» я хочу получить событие (в частности, «CollectionChanged»). Но это то, чего я не знаю.

Чтобы получить 'o', я использовал отражение следующим образом:

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

Первым предложенным мною предложением было «GetRaisedMethod», которое является свойством EventInfo.

Итак, чтобы получить EventInfo, я использовал следующий код:

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

Кажется, что 'evi' содержит правильную информацию, но если я использую эту строку:

var invocation = evi.GetRaiseMethod();

Я получаю ноль. Но я уже читал об этом в вопросах, которые уже просматривал, и, кажется, это очень часто встречается. Тем не менее, я подумал, что должен попробовать.

Затем я пошел другим путем, который был представлен в другом вопросе, чтобы посмотреть, сработало ли это. Это выглядит следующим образом:

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

Теперь это вызвало для меня исключение, которое я сузил до второй из этих двух строк. Сообщение было следующим:

"Операции с поздним связыванием не могут быть выполнены для полей с типами, для которых Type.ContainsGenericParameters имеет значение true."

И поэтому я решил, что это событие с общими параметрами. Но я не смог найти нигде такого решения. Конечно, для метода вы можете использовать MethodInfo.MakeGenericMethod (), но в EventInfo такого нет.

Все, что я хочу - это иметь возможность подписаться на это событие, как обычно, но пока оно ускользает от меня.

Вы также можете подумать, что я могу сделать что-то вроде этого:

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

Но я не могу. Я перепробовал все варианты вышеупомянутых (без угловых скобок, с моим собственным типом (типа Type, который является типом элемента в коллекции). Ни один не работал для меня. Конечно, это было бы проще, но я не нашел пути с таким подходом.

1 Ответ

0 голосов
/ 07 ноября 2018

Метод EventInfo.AddEventHandler может сделать работу за вас, взгляните на этот пример:

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" );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...