2011-02-17 21 views
3

當將處理程序不加區分地添加到對象的事件中時,我意識到我可以根據需要多次將同一個處理程序附加到事件。這意味着處理程序在每次連接時都會被調用一次。在.NET中使用事件處理程序

我不知道這些東西:

  • 有沒有一種方式來看待它的處理程序已被添加到一個對象的事件?
  • 是否可以從事件中刪除所有處理程序?
  • 事件與其處理程序之間的這些關聯存儲在哪裏?
+1

清除處理程序:http://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control – 2011-02-17 19:06:22

回答

2

如果該事件被標記爲C#事件關鍵字並沒有從對象之外的方式來看到用戶 - 必要的信息是不可見的。

從裏面可以做到,儘管它很複雜,依賴於可能會改變的實現細節(儘管它們還沒有)。

一種可能對您有用的解決方法是,它的有效期爲刪除不存在的處理程序 - 不會引發異常。

所以這段代碼是有效的:

myConnection.Closing -= ConnectionClosingHandler; 
myConnection.Closing += ConnectionClosingHandler; 

如果您已經訂閱了該事件,第一行刪除訂閱。
如果您是而不是已訂閱該事件,則第一行不做任何事情。

第二行然後掛鉤一個新的訂閱,並保證不會多次通知。

要回答你的最後一個項目符號點,當你宣佈一個正常的事件:

public event PropertyChangedEventHandler Changed; 

編譯器創建PropertyChangedEventHandler類型的成員變量,它存儲所有的用戶。如果你願意,你可以接管存儲:

public event PropertyChangedEventHandler Changed 
{ 
    add { ... } 
    remove { ... } 
} 

採用-=+=修改的訂購不是語法糖 - 代表是不可改變的,而當你添加或刪除處理程序返回一個新的實例。看看DelegateMulticastDelegate(這兩個MSDN鏈接)瞭解更多信息如何工作。

1

事件與其處理程序之間的相關性存儲在事件本身上。當您訪問該事件時,該信息實際上被複制到方法組中。這就是爲什麼你應該說:

var onclick = Click; 
if (onclick != null) onclick(); 

如果我訪問的Click事件,而不是兩次使用中間onclick變量,我將造成任何事件被複制兩次。另外,在多線程場景中,如果有人在檢查Click != null和調用處理程序之間刪除了一個處理程序,我最終可能會拋出異常。

如果您已經知道要刪除哪一個處理器,它很容易刪除處理程序:

EventHandler handler1 = (sender, e) => Console.WriteLine("test"); 
Click += handler1; 
Click -= handler1; 

有一種方式來獲得有關已添加到對象的事件每個處理程序的一些基本信息,通過GetInvocationList

foreach(var handler in Click.GetInvocationList()) 
    Console.WriteLine(handler.Method.ToString()); 

但是,你出的信息是在委託對象的形式。可以調用它(如果要捕獲一個處理程序引發的任何異常,並繼續調用其餘的處理程序,這會非常有用),但C#不提供簡單的方法來僅基於此信息從處理中刪除處理程序。 How to remove all event handlers from a control的一些答案似乎表明您可以使用Reflection來完成它,或者您可以使用Visual Basic的RemoveHandler命令。