C#でイベントサブスクリプションをクリアするにはどうすればよいですか?
質問
次のC#クラスを取得します。
c1 {
event EventHandler someEvent;
}
c1
の someEvent
イベントに対するサブスクリプションが多数あり、それらをすべてクリアしたい場合、これを達成する最良の方法は何ですか? このイベントへのサブスクリプションは、ラムダ/匿名デリゲートである可能性があることも考慮してください。
現在、私の解決策は、 someEvent
をnullに設定する c1
に ResetSubscriptions()
メソッドを追加することです。これが目に見えない結果をもたらすかどうかはわかりません。
解決
クラス内から、(非表示の)変数をnullに設定できます。 null参照は、空の呼び出しリストを効果的に表す標準的な方法です。
クラスの外部からこれを行うことはできません-イベントは基本的に" subscribe"を公開しますおよび「登録解除」それだけです。
フィールドのようなイベントが実際に何をしているのかを知っておく価値があります-それらは変数とを同時に作成しています。クラス内で、変数を参照することになります。外部からイベントを参照します。
詳細については、イベントとデリゲートに関する記事をご覧ください。
他のヒント
「someEvent」をnullに設定するメソッドをc1に追加します...
class c1
{
event EventHandler someEvent;
ResetSubscriptions() {someEvent = null;}
}
class c1
{
event EventHandler someEvent;
ResetSubscriptions() {someEvent = delegate{};}
}
nullよりデリゲート{}を使用した方が良い
クラス内でイベントをnullに設定すると機能します。クラスを破棄するときは、常にイベントをnullに設定する必要があります。GCはイベントに問題があり、ダングリングイベントがある場合、破棄されたクラスをクリーンアップしない場合があります。
すべてのサブスクライバをクリアするベストプラクティスは、この機能を外部に公開する場合は、別のパブリックメソッドを追加して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.
}
Delegate.RemoveまたはDelegate.RemoveAllメソッドを使用してこれを実現できます。
概念的な拡張退屈なコメント。
むしろ、「イベントハンドラ」という言葉を使用します。 「イベント」の代わりにまたは「デリゲート」。そして、「イベント」という言葉を使用しました他のもののために。一部のプログラミング言語(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;
そして、その「メッセージ」に応答するために、「イベントハンドラ」単一のデリゲートであるか複数のデリゲートであるかにかかわらず、応答します。
概要: &quot;イベント&quot;は「質問」、「イベントハンドラ」です。答えです。
これは私の解決策です:
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()){/*...*/}
パターンを使用して、呼び出しリストのすべてのメンバーの登録を解除する必要があります。 。
すべてのイベントを削除し、イベントが「アクション」であると仮定します。タイプ:
Delegate[] dary = TermCheckScore.GetInvocationList();
if ( dary != null )
{
foreach ( Delegate del in dary )
{
TermCheckScore -= ( Action ) del;
}
}