Comment obtenir un object délégué à partir d’un EventInfo?

Je dois obtenir tous les événements de la classe actuelle et connaître les méthodes qui y sont associées. Ici, j’ai quelques réponses sur la façon de procéder , mais je ne sais pas comment obtenir le delegate lorsque tout ce que j’ai est le EventInfo .

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

Est-il possible d’avoir un délégué avec EventInfo ? Comment?

L’instruction var events = GetType().GetEvents(); vous donne une liste d’objects EventInfo associés au type actuel, pas l’instance actuelle en tant que telle. Ainsi, l’object EventInfo ne contient pas d’informations sur l’instance actuelle et ne connaît donc pas les delegates connectés.

Pour obtenir les informations souhaitées, vous devez obtenir le champ de sauvegarde du gestionnaire d’événements sur votre instance actuelle. Voici comment:

 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; } } 

Alors maintenant, votre code d’appel peut ressembler à ceci:

 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(); } } 

La sortie de ce qui précède est:

 MyHandler b__0 

Je suis sûr que vous pouvez manipuler le code si vous souhaitez renvoyer le délégué plutôt que les informations de méthode, etc.

J’espère que ça aide.

Pour mon cas, la valeur du champ (classe ToolSsortingpMenuItem , champ EventClick ) frustrant est de type object, pas de délégué. Je devais recourir à la propriété Events mentionnée par Les dans sa réponse, comme je l’ai appris d’ ici . Dans ce cas, le champ EventClick contient uniquement la clé de EventHandlerList stockée dans cette propriété.

Quelques autres remarques:

  • La règle fieldName = "Event" + eventName j’ai employé ne fonctionnera pas dans tous les cas. Malheureusement, il n’existe pas de règle commune pour lier le nom de l’événement au nom du champ. Vous pouvez essayer d’utiliser un dictionnaire statique pour le mappage, similaire à cet article .
  • Je ne suis jamais vraiment sûr du BindingFlags. Dans un autre scénario, vous devrez peut-être les ajuster.

     ///  /// 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, ssortingng 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; } 

Comme pour Enigmativity , la liste d’invocation peut être trouvée pour d’autres classes, pas seulement pour la classe actuelle …

  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; } 

… tant que les gestionnaires d’événements sont déclarés dans la classe, comme nous le voyons ci-dessus. Mais considérons la classe Control où EventHandlerList est stocké dans la propriété “Events” et chaque nom de champ d’événement commence par “Event” suivi du nom de l’événement. Ensuite, il y a les classes dérivées de formulaire qui semblent gérer les événements différemment. Nourriture pour la pensée.