获取编译器生成的事件代理
问题描述:
我需要知道哪些处理程序被子集化为ObservableCollection类的CollectionChanged事件。我发现的唯一解决方案是在事件的委托上使用Delegate.GetInvocationList()。问题是,我无法获得Reflection来查找编译器生成的委托。 AFAIK代表与事件具有相同的名称。我用下面的代码:获取编译器生成的事件代理
PropertyInfo notifyCollectionChangedDelegate = collection.GetType().GetProperty("CollectionChanged", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
答
它不是一个财产,它是一个领域。此作品:
using System;
using System.Collections.ObjectModel; // Add reference to WindowsBase
using System.Collections.Specialized;
using System.Reflection;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
var coll = new ObservableCollection<int>();
coll.CollectionChanged += coll_CollectionChanged;
coll.Add(42);
FieldInfo fi = coll.GetType().GetField("CollectionChanged", BindingFlags.NonPublic | BindingFlags.Instance);
NotifyCollectionChangedEventHandler handler = fi.GetValue(coll) as NotifyCollectionChangedEventHandler;
handler.Invoke(coll, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
static void coll_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
Console.WriteLine("Changed {0}", e.Action);
}
}
}
请勿使用它。
答
整个事件的一点是,它们封装的发布/订阅本质没有暴露出当前订阅处理程序。你不需要知道订阅的处理程序 - 如果你这样做,你应该使用自己的类型而不是ObservableCollection
。你想做什么?
没有什么可以保证是一个编译器生成的委托字段。它可能没有使用类域事件来声明 - 事实上,甚至可能根本没有一个单独的域用于支持代理。 (可能有,因为在ObservableCollection
上没有太多事件 - 但WinForms控件使用延迟分配的映射来避免每个事件必须有一个字段,当大多数事件不会有订阅处理程序时。)
我的目标是管理订阅NotifyCollectionChanged事件,但我只需要订阅一次。我不想管理每个ObservableCollection的布尔字段来保存这些信息。 (订阅发生在多次被调用的地方。) 所以最简单的是检查我是否已经订阅了一个处理程序。要么我在这里丢失了一些非常简单的东西,要么.net框架事件真的需要公开一个给予订阅处理程序的属性。 (顺便说一句,我发现一篇文章描述了WinForms委托系统,但我需要这个。) – 2010-04-12 13:40:12