2008-09-30 33 views
125

看看下面的C#類:如何清除C#中的事件訂閱?

c1 { 
event EventHandler someEvent; 
} 

如果有大量的訂閱到c1someEvent事件,我想清楚了他們,什麼是實現這一目標的最佳途徑? 另請考慮對此事件的訂閱可能是lambda /匿名代理。

目前我的解決方案是將ResetSubscriptions()方法添加到c1,將someEvent設置爲空。我不知道這是否有任何看不見的後果。

回答

164

從類內部,您可以將(隱藏)變量設置爲null。空引用是有效地表示空調用列表的規範方式。

從課外,你不能這樣做 - 事件基本上暴露「訂閱」和「取消訂閱」,就是這樣。

值得注意的是場外事件實際上在做什麼 - 他們在同一時間創建變量事件。在課堂中,你最終引用變量。你從外面引用這個事件。

查看我的article on events and delegates瞭解更多信息。

28

使用Delegate.Remove或Delegate.RemoveAll方法添加一個方法C1,將設置「someEvent」爲空...

class c1 
{ 
    event EventHandler someEvent; 
    ResetSubscriptions() {someEvent = null;} 
} 
+0

你確定分配null會清除調用列表嗎? – leppie 2008-09-30 15:37:16

+0

這就是我所看到的行爲。正如我在我的問題中所說的,我不知道我是否忽略了某些事情。 – programmer 2008-09-30 15:42:54

5

你可以做到這一點。

+6

我不相信這將適用於lambda表達式或匿名代表。 – programmer 2008-09-30 15:45:13

+3

這將是一個很好的建議,但你沒有例子... – 2013-11-27 23:25:45

5

在類作品中將事件設置爲null。當你處理一個類時,你應該總是將事件設置爲null,GC有事件的問題,並且如果事件懸而未決,可能無法清理處置的類。

3

概念性延長無聊的評論。

我寧願使用「事件處理程序」而不是「事件」或「委託」這個詞。其他的東西使用「事件」一詞。在一些編程語言(VB.NET,Object Pascal,Objective-C)中,「事件」被稱爲「消息」或「信號」,甚至有一個「消息」關鍵字和特定的糖語法。

const 
    WM_Paint = 998; // <-- "question" can be done by several talkers 
    WM_Clear = 546; 

type 
    MyWindowClass = class(Window) 
    procedure NotEventHandlerMethod_1; 
    procedure NotEventHandlerMethod_17; 

    procedure DoPaintEventHandler; message WM_Paint; // <-- "answer" by this listener 
    procedure DoClearEventHandler; message WM_Clear; 
    end; 

而且,爲了迴應稱「消息」,一個「事件處理程序」響應,無論是單委託或多個委託。

總結: 「事件」是「問題」,「事件處理程序」是答案。

6

清除所有訂閱者的最佳做法是,如果要將此功能公開給外部,請將someEvent設置爲null,方法是添加另一個公共方法。這沒有看不到的後果。前提是要記住用關鍵字'event'聲明SomeEvent。

請參見本書 - C#4.0中概括地說,第125頁

有人在這裏建議用Delegate.RemoveAll方法。如果你使用它,示例代碼可以遵循下面的表格。但它真的很愚蠢。ClearSubscribers()函數裏面爲什麼不是SomeEvent=null

public void ClearSubscribers() 
    { 
      SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent);// Then you will find SomeEvent is set to null. 
    } 
0

刪除所有事件,假設該事件是一個 「動作」 類型:

Delegate[] dary = TermCheckScore.GetInvocationList(); 

if (dary != null) 
{ 
    foreach (Delegate del in dary) 
    { 
     TermCheckScore -= (Action) del; 
    } 
} 
6
class c1 
{ 
    event EventHandler someEvent; 
    ResetSubscriptions() {someEvent = delegate{};} 
} 

這是更好地使用委託{}不是空

1

這是我的解決方案:

public class Foo : IDisposable 
{ 
    private event EventHandler _statusChanged; 
    public event EventHandler StatusChanged 
    { 
     add 
     { 
      _statusChanged += value; 
     } 
     remove 
     { 
      _statusChanged -= value; 
     } 
    } 

    public void Dispose() 
    { 
     _statusChanged = null; 
    } 
} 

您需要撥打Dispose()或使用using(new Foo()){/*...*/}模式來取消訂閱調用列表的所有成員。