添加到委托的附加信息
Additional information added to a delegate
也许这个问题已经被问过很多次,也已经解决了很多次,但我可能用错了术语,因为到目前为止我还没有想出答案。
所以我有一个 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' 的元素发生更改时调用。我可以调用消息框等,但我希望在此操作中捕获某种信息。特别是,这一切所在的 class 有一个 ID,它是一个简单的 int。我想捕获这个 int 并在动作中使用它。由于它的自动化特性,我似乎无法添加任何其他参数,所以我不确定如何管理它。
编辑:
我想我要做的是创建一个新项目并尝试找出我遇到的问题。只是为了弄清楚这在哪里结束,我尝试简单地在声明事件的 class 中存在的事件中引用 属性,我得到了 'cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type' 异常。我还会看到问题吗?这就是我想知道的。
代码在这里:Code
这很简单,只是一个测试 class。所有其余代码(MainWindow.xaml.cs 因为它是 WPF 项目)是创建 TestClass 的实例,将 TestInt 设置为 10001,然后在该实例上调用 TestMethod。
事件中没有 'this.TestInt',它工作正常。有了它,异常依旧。
由于 lambda 捕获会导致创建状态对象,因此在从旧委托创建新委托时必须考虑 Target
。所以你需要使用下面的 CreateDelegate(Type, Object, MethodInfo)
重载。即使对于没有目标对象的委托,此方法也是安全的,msdn 告诉我们有关对象参数的信息:
The object to which the delegate is bound, or null to treat method as static (Shared in 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);
也许这个问题已经被问过很多次,也已经解决了很多次,但我可能用错了术语,因为到目前为止我还没有想出答案。
所以我有一个 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' 的元素发生更改时调用。我可以调用消息框等,但我希望在此操作中捕获某种信息。特别是,这一切所在的 class 有一个 ID,它是一个简单的 int。我想捕获这个 int 并在动作中使用它。由于它的自动化特性,我似乎无法添加任何其他参数,所以我不确定如何管理它。
编辑:
我想我要做的是创建一个新项目并尝试找出我遇到的问题。只是为了弄清楚这在哪里结束,我尝试简单地在声明事件的 class 中存在的事件中引用 属性,我得到了 'cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type' 异常。我还会看到问题吗?这就是我想知道的。
代码在这里:Code
这很简单,只是一个测试 class。所有其余代码(MainWindow.xaml.cs 因为它是 WPF 项目)是创建 TestClass 的实例,将 TestInt 设置为 10001,然后在该实例上调用 TestMethod。
事件中没有 'this.TestInt',它工作正常。有了它,异常依旧。
由于 lambda 捕获会导致创建状态对象,因此在从旧委托创建新委托时必须考虑 Target
。所以你需要使用下面的 CreateDelegate(Type, Object, MethodInfo)
重载。即使对于没有目标对象的委托,此方法也是安全的,msdn 告诉我们有关对象参数的信息:
The object to which the delegate is bound, or null to treat method as static (Shared in 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);