获取编译器生成的事件代理

问题描述:

我需要知道哪些处理程序被子集化为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控件使用延迟分配的映射来避免每个事件必须有一个字段,当大多数事件不会有订阅处理程序时。)

+0

我的目标是管理订阅NotifyCollectionChanged事件,但我只需要订阅一次。我不想管理每个ObservableCollection的布尔字段来保存这些信息。 (订阅发生在多次被调用的地方。) 所以最简单的是检查我是否已经订阅了一个处理程序。要么我在这里丢失了一些非常简单的东西,要么.net框架事件真的需要公开一个给予订阅处理程序的属性。 (顺便说一句,我发现一篇文章描述了WinForms委托系统,但我需要这个。) – 2010-04-12 13:40:12