Дополнительная информация, добавленная к делегату - PullRequest
0 голосов
/ 06 ноября 2018

Возможно, этот вопрос задавался и решался много раз, но, возможно, я использую неправильные термины, поскольку до сих пор не нашел ответа.

Итак, у меня есть ObservableCollection, и я использовал отражение, чтобы вызвать обработчик события CollectionChanged.

Это выглядит так ('o' - это рассматриваемая коллекция ObservableCollection, также полученная с помощью отражения):

                EventInfo evi = o.GetType().GetEvent("CollectionChanged", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                var eventHandler = new Action<object, NotifyCollectionChangedEventArgs>(
                    (s, a) => 
                    {
                        // Event code here
                    });

                 var del = Delegate.CreateDelegate(evi.EventHandlerType, eventHandler.Method);

                 evi.AddEventHandler(o, del);

Вызов этого действия автоматизирован и вызывается при изменении элементов свойства 'o'. Я могу вызывать окна сообщений и тому подобное, но я хочу собрать некоторую информацию внутри этого действия. В частности, класс, в котором находится все это, имеет идентификатор, который является простым int. Я хотел бы захватить этот int и использовать его в действии. Кажется, я не могу добавить какие-либо дополнительные параметры из-за его автоматического характера, поэтому я не уверен, как с этим справиться.

Edit:

Я думал, что сделаю новый проект и попытаюсь изолировать проблему, которая у меня была. Просто чтобы понять, где это закончилось, я попытался просто сослаться на свойство в событии, которое существовало в классе, в котором было объявлено событие, и я получил сообщение «невозможно связать с целевым методом, потому что его подпись или прозрачность безопасности несовместимы». с этим типом делегата исключение. Я все еще вижу проблему? Вот что я хотел узнать.

Код здесь: Код

Это довольно просто и это просто тестовый класс. Все остальное, что делает код (MainWindow.xaml.cs, поскольку это проект WPF), создает экземпляр TestClass, устанавливает TestInt равным 10001, а затем вызывает TestMethod для этого экземпляра.

Без 'this.TestInt' в событии все работает нормально. С этим исключением все еще там.

1 Ответ

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

Поскольку лямбда-захват приводит к созданию объекта состояния, необходимо учитывать Target при создании нового делегата из старого. Так что вам нужно использовать следующую CreateDelegate(Type, Object, MethodInfo) перегрузку. Этот метод безопасен даже для делегатов без целевого объекта, msdn сообщает нам о параметре объекта:

Объект, к которому привязан делегат, или значение NULL для обработки метода как статического (Shared в Visual Basic).

Следующая адаптация вашего кода должна сделать эту работу:

var o = p.GetValue(this,null);
EventInfo eventInfo = t.GetEvent("CollectionChanged", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

var handler = new Action<object, NotifyCollectionChangedEventArgs>((s, a) => { Console.WriteLine("Changed + " + this.TestInt.ToString()); });

Delegate del = Delegate.CreateDelegate(eventInfo.EventHandlerType, handler.Target, handler.Method);

eventInfo.AddEventHandler(o, del);
...