2010-09-23 13 views
7

Potrzebuję uzyskać wszystkie zdarzenia z bieżącej klasy i dowiedzieć się, jakie metody subskrybują. Here I got some answers on how to do that, ale nie wiem, jak mogę uzyskać delegate, gdy wszystko, co mam, to EventInfo.Jak uzyskać obiekt uczestnika z EventInfo?

var events = GetType().GetEvents(); 

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

Czy to możliwe, aby uzyskać delegata z EventInfo? W jaki sposób?

+1

Cytowanie od najwyższej głosowało odpowiedź na wcześniejsze pytanie: „Teraz załóżmy, że może próbować odnaleźć ciało«Dodaj»obsługi, dekompilować go i wyszło jak obsługi zdarzeń są poddawane zapisane i pobrać je w ten sposób ... ** ale nie rób ** Tworzysz dużo pracy, tylko po to, aby przerwać hermetyzację. ** ** przeprojektuj swój kod **, aby nie było potrzeby Zrób to." Z całego serca się zgadzam. –

Odpowiedz

12

Instrukcja var events = GetType().GetEvents(); wyświetla listę obiektów związanych z bieżącym typem, a nie bieżącą instancję jako taką. Tak więc obiekt EventInfo nie zawiera informacji o bieżącej instancji, a tym samym nie wie o połączonych delegatach.

Aby uzyskać potrzebne informacje, należy uzyskać pole zaplecza obsługi zdarzeń w bieżącej instancji. Oto jak:

public class MyClass 
{ 
    public event EventHandler MyEvent; 

    public IEnumerable<MethodInfo> GetSubscribedMethods() 
    { 
     Func<EventInfo, FieldInfo> 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; 
    } 
} 

Teraz Twój kod wywołujący może wyglądać następująco:

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

Wyjście z powyższego jest:

MyHandler 
<Execute>b__0 

Jestem pewien, że można jig wokół z kod, jeśli chcesz zwrócić delegata zamiast informacji o metodzie, itp.

Mam nadzieję, że to pomoże.

+0

To jest naprawdę zagadkowe, nawet nie mogę go przeczytać. – jcmcbeth

+0

@jcmcbeth - Która część jest tajemnicza? – Enigmativity

+1

Twoja EventInfo na delegata FieldInfo (ei2fi) wydaje się nie działać dla [zdarzeń z niestandardowym dodawaniem i usuwaniem] (http://msdn.microsoft.com/en-us/magazine/cc163533.aspx). –

2

Podobnie Enigmativity lista inwokacja można znaleźć w innych klasach, nie tylko bieżącej klasy ...

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

... dopóki obsługi zdarzeń są zadeklarowane w klasie jako widzimy powyżej. Ale weź pod uwagę klasę Control, w której właściwość EventHandlerList jest przechowywana we właściwości "Events", a nazwa każdego zdarzenia zaczyna się od "Event", po którym następuje nazwa zdarzenia. Są też klasy pochodne Form, które zdają się zarządzać zdarzeniami jeszcze inaczej. Jedzenie dla myśli.

2

Na moim przypadku wartość pola (klasa ToolStripMenuItem, pole EventClick) frustratingly jest typu obiektu, a nie przekazać. Musiałem odwołać się do własności Events, którą Les wspomniał w swojej odpowiedzi, w sposób jaki otrzymałem od here. Pole EventClick w tym przypadku zawiera tylko klucz do właściwości EventHandlerList przechowywanej w tej właściwości.

Niektóre inne uwagi:

  • Reguła fieldName = "Event" + eventName I rachunek nie będzie działać w każdym przypadku. Niestety nie ma wspólnej reguły dla łączenia nazwy zdarzenia z nazwą pola. Możesz spróbować użyć statycznego słownika do mapowania, podobnego do this article.
  • Nigdy nie jestem do końca pewien co do BindingFlags. W innym scenariuszu może być konieczne ich dostosowanie.

    /// <summary> 
    /// Gets the EventHandler delegate attached to the specified event and object 
    /// </summary> 
    /// <param name="obj">object that contains the event</param> 
    /// <param name="eventName">name of the event, e.g. "Click"</param> 
    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; 
    } 
    
+0

Pomógł mi tonę. Dzięki! – Law

Powiązane problemy