如何从EventInfo获取委托对象?

我需要从当前类中获取所有事件,并找出订阅它的方法。 在这里,我得到了一些关于如何做到这一点的答案 ,但我不知道如何获得delegate ,而我所拥有的只是EventInfo

 var events = GetType().GetEvents(); foreach (var e in events) { Delegate d = e./*GetDelegateFromThisEventInfo()*/; var methods = d.GetInvocationList(); } 

是否可以通过EventInfo获得委托? 怎么样?

语句var events = GetType().GetEvents(); 获取与当前类型关联的EventInfo对象列表,而不是当前实例本身。 因此, EventInfo对象不包含有关当前实例的信息,因此它不知道有线EventInfo

要获取所需信息,您需要获取当前实例上事件处理程序的支持字段。 这是如何做:

 public class MyClass { public event EventHandler MyEvent; public IEnumerable GetSubscribedMethods() { Func ei2fi = ei => this.GetType().GetField(ei.Name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); return from eventInfo in this.GetType().GetEvents() let eventFieldInfo = ei2fi(eventInfo) let eventFieldValue = (System.Delegate)eventFieldInfo.GetValue(this) from subscribedDelegate in eventFieldValue.GetInvocationList() select subscribedDelegate.Method; } } 

所以现在你的调用代码看起来像这样:

 class GetSubscribedMethodsExample { public static void Execute() { var instance = new MyClass(); instance.MyEvent += new EventHandler(MyHandler); instance.MyEvent += (s, e) => { }; instance.GetSubscribedMethods() .Run(h => Console.WriteLine(h.Name)); } static void MyHandler(object sender, EventArgs e) { throw new NotImplementedException(); } } 

上面的输出是:

 MyHandler b__0 

如果您希望返回代理而不是方法信息等,我相信您可以使用代码进行浏览。

我希望这有帮助。

对于我的情况,字段值(类ToolStripMenuItem ,字段EventClick )令人沮丧地是对象类型,而不是委托。 我不得不求助于Les在他的回答中提到的Events ,就像我从这里得到的那样。 在这种情况下,字段EventClick仅保存存储在此属性中的EventHandlerList的键。

其他一些评论:

  • 我使用的规则fieldName = "Event" + eventName在每种情况下都不起作用。 遗憾的是,没有将事件名称链接到字段名称的通用规则。 您可能会尝试使用静态字典进行映射,类似于本文 。
  • 我不太确定BindingFlags。 在另一种情况下,您可能需要调整它们。

     ///  /// Gets the EventHandler delegate attached to the specified event and object ///  /// object that contains the event /// name of the event, eg "Click" public static Delegate GetEventHandler(object obj, string eventName) { Delegate retDelegate = null; FieldInfo fi = obj.GetType().GetField("Event" + eventName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.IgnoreCase); if (fi != null) { object value = fi.GetValue(obj); if (value is Delegate) retDelegate = (Delegate)value; else if (value != null) // value may be just object { PropertyInfo pi = obj.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance); if (pi != null) { EventHandlerList eventHandlers = pi.GetValue(obj) as EventHandlerList; if (eventHandlers != null) { retDelegate = eventHandlers[value]; } } } } return retDelegate; } 

Enigmativity类似,可以为其他类找到调用列表,而不仅仅是当前类…

  private void testit() { WithEvents we = new WithEvents(); we.myEvent += new EventHandler(we_myEvent); we.myEvent += new EventHandler(we_myEvent2); foreach (EventInfo ev in we.GetType().GetEvents()) { FieldInfo fi = we.GetType().GetField(ev.Name, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy); Delegate del = (Delegate)fi.GetValue(we); var list = del.GetInvocationList(); foreach (var d in list) { Console.WriteLine("{0}", d.Method.Name); } } } void we_myEvent(object sender, EventArgs e) { } void we_myEvent2(object sender, EventArgs e) { } public class WithEvents { public event EventHandler myEvent; } 

…只要事件处理程序在类中声明,如上所示。 但是考虑将EventHandlerList存储在“Events”属性中的Control类,每个事件字段名称以“Event”开头,后跟事件名称。 然后是Form派生类似乎以不同方式管理事件。 值得深思。