146

次の C# クラスを使用します。

c1 {
 event EventHandler someEvent;
}

c1さんのイベントにたくさんのサブスクリプションがあり、someEventそれらをすべてクリアしたい場合、これを達成するための最良の方法は何ですか? また、このイベントへのサブスクリプションがラムダ/匿名デリゲートである可能性があることも考慮してください。

現在、私の解決策は、nullに設定するResetSubscriptions()メソッドを追加することです。これが目に見えない結果をもたらすかどうかはわかりません。c1someEvent

4

10 に答える 10

186

クラス内から、(隠し) 変数を null に設定できます。null 参照は、空の呼び出しリストを効果的に表す正規の方法です。

クラスの外からは、これを行うことはできません。イベントは基本的に「購読」と「購読解除」を公開するだけです。

フィールドのようなイベントが実際に何をしているのかを知っておくことは価値があります - それらは変数イベントを同時に作成しています。クラス内では、変数を参照することになります。外部から、イベントを参照します。

詳細については、イベントとデリゲートに関する私の記事を参照してください。

于 2008-09-30T16:05:02.233 に答える
34

「someEvent」を null に設定するメソッドを c1 に追加します。

public class c1
{
    event EventHandler someEvent;
    public ResetSubscriptions() => someEvent = null;    
}
于 2008-09-30T15:33:46.550 に答える
6

クラス内でイベントを null に設定すると機能します。クラスを破棄するときは、常にイベントを null に設定する必要があります。GC にはイベントに関する問題があり、破棄されたクラスにぶら下がっているイベントがある場合、破棄されたクラスをクリーンアップできない可能性があります。

于 2008-10-01T11:17:04.630 に答える
6

すべてのサブスクライバーをクリアするベスト プラクティスは、この機能を外部に公開する場合、別のパブリック メソッドを追加して someEvent を null に設定することです。これには目に見えない結果はありません。前提条件は、キーワード 'event' を使用して SomeEvent を宣言することを忘れないことです。

本 - C# 4.0 の概要、125 ページを参照してください。

ここでメソッドを使用することを提案した人がいますDelegate.RemoveAll。これを使用する場合、サンプル コードは次の形式に従うことができます。しかし、それは本当に愚かです。関数SomeEvent=null内だけではないのはなぜですか?ClearSubscribers()

public void ClearSubscribers ()
{
   SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent);
   // Then you will find SomeEvent is set to null.
}
于 2012-10-16T12:00:05.027 に答える
5

これは、Delegate.Remove または Delegate.RemoveAll メソッドを使用して実現できます。

于 2008-09-30T15:36:21.320 に答える
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;

そして、その「メッセージ」に応答するために、単一のデリゲートまたは複数のデリゲートのいずれであっても、「イベント ハンドラー」が応答します。

要約: 「イベント」は「質問」、「イベント ハンドラ」は回答です。

于 2011-03-24T18:39:12.553 に答える
0

イベントが「アクション」タイプであると仮定して、すべてのイベントを削除します。

Delegate[] dary = TermCheckScore.GetInvocationList();

if ( dary != null )
{
    foreach ( Delegate del in dary )
    {
        TermCheckScore -= ( Action ) del;
    }
}
于 2013-12-20T20:00:54.253 に答える
0

これが私の解決策です:

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()){/*...*/}

于 2018-03-05T07:14:39.347 に答える