2010-09-23 41 views
7

Tôi cần nhận tất cả các sự kiện từ lớp hiện tại và tìm hiểu các phương pháp đăng ký nó. Here I got some answers on how to do that, nhưng tôi không biết làm thế nào tôi có thể nhận được delegate khi tất cả tôi có là EventInfo.Làm thế nào để có được một đối tượng đại biểu từ một EventInfo?

var events = GetType().GetEvents(); 

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

Có thể ủy quyền với EventInfo không? Làm sao?

+1

Trích dẫn từ câu trả lời cao nhất bình chọn trên câu hỏi trước của bạn: "Bây giờ tôi giả sử bạn có thể thử để tìm ra cơ thể của 'add' xử lý, biên soạn lại nó và tìm ra cách xử lý sự kiện đang được lưu trữ, và lấy chúng theo cách đó ... ** nhưng xin đừng ** Bạn đang tạo ra rất nhiều công việc, chỉ để phá vỡ đóng gói. Chỉ cần ** thiết kế lại mã của bạn ** để bạn không cần phải làm cái này." Tôi hết lòng đồng ý. –

Trả lời

12

Tuyên bố var events = GetType().GetEvents(); cho bạn danh sách EventInfo đối tượng được liên kết với loại hiện tại, không phải là cá thể hiện tại. Vì vậy, đối tượng EventInfo không chứa thông tin về cá thể hiện tại và do đó nó không biết về các đại biểu có dây.

Để nhận thông tin bạn muốn, bạn cần lấy trường sao lưu cho trình xử lý sự kiện trên phiên bản hiện tại của bạn. Đây là cách:

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

Bây giờ mã gọi của bạn có thể trông như thế này:

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

Sản lượng từ trên là:

MyHandler 
<Execute>b__0 

tôi chắc chắn rằng bạn có thể JIG xung quanh với mã nếu bạn muốn trả lại đại biểu thay vì thông tin về phương thức, v.v.

Tôi hy vọng điều này sẽ hữu ích.

+0

Điều này thực sự khó hiểu, tôi thậm chí không thể đọc nó. – jcmcbeth

+0

@jcmcbeth - Phần nào khó hiểu? – Enigmativity

+1

Sự kiện EventInfo của bạn vào FieldInfo (ei2fi) dường như không hoạt động đối với [sự kiện có thêm và xóa tùy chỉnh] (http://msdn.microsoft.com/en-us/magazine/cc163533.aspx). –

2

Tương tự như Enigmativity, danh sách gọi có thể được tìm thấy cho các lớp khác, không chỉ các lớp hiện tại ...

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

... miễn là xử lý sự kiện được khai báo trong lớp như chúng ta thấy ở trên. Nhưng hãy xem xét lớp Điều khiển nơi EventHandlerList được lưu trữ trong thuộc tính "Sự kiện" và mỗi tên trường sự kiện bắt đầu bằng "Sự kiện", sau đó là tên sự kiện. Sau đó, có các lớp dẫn xuất biểu mẫu dường như quản lý các sự kiện khác nhau. Thức ăn cho sự suy nghĩ.

2

Đối với trường hợp của tôi, giá trị trường (loại ToolStripMenuItem, trường EventClick) bực bội là đối tượng kiểu, không được ủy quyền. Tôi đã phải nghỉ mát đến tài sản Events mà Les đã đề cập trong câu trả lời của mình, theo cách tôi nhận được từ here. Trường EventClick trong trường hợp này chỉ giữ khóa cho EventHandlerList được lưu trữ trong thuộc tính này.

Một số nhận xét khác:

  • Nguyên tắc fieldName = "Event" + eventName tôi sử dụng sẽ không hoạt động trong mọi trường hợp. Rất tiếc, không có quy tắc chung nào để liên kết tên sự kiện với tên trường. Bạn có thể thử sử dụng một từ điển tĩnh để lập bản đồ, tương tự như this article.
  • Tôi không bao giờ chắc chắn về BindingFlags. Trong một kịch bản khác, bạn có thể phải điều chỉnh chúng.

    /// <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

Giúp tôi ra một tấn. Cảm ơn! – Law

Các vấn đề liên quan