web-dev-qa-db-ja.com

「匿名」イベントハンドラーの登録を解除するにはどうすればよいですか

イベントを聞いたら言う:

Subject.NewEvent += delegate(object sender, NewEventArgs e)
{
    //some code
}); 

このイベントの登録を解除するにはどうすればよいですか?それとも単にメモリをリークさせますか?

37
P.K

イベントの登録を解除する必要がある場合は、イベントハンドラーの匿名デリゲートを避けることをお勧めします。

これは、これをローカルメソッドに割り当てる方がよい場合の1つです。つまり、イベントからクリーンにサブスクライブを解除できます。

24
Reed Copsey

匿名デリゲートのインスタンスに名前を付けます。

EventHandler<NewEventArg> handler = delegate(object sender, NewEventArgs e)
{
    //some code
};

Subject.NewEvent += handler;
Subject.NewEvent -= handler;
42
dtb

最初の呼び出しでハンドラーを削除するには:

//SubjectType Subject = ..... already defined if using (2)

EventHandler handler = null;
handler = delegate(object sender, EventArgs e)
{
    // (1)
    (sender as SubjectType).NewEvent -= handler;
    // or
    // (2) Subject.NewEvent -= handler;

    // do stuff here
};

Subject.NewEvent += handler;
21
Ian

イベントのすべてのリスナーから登録を解除するためのメソッドを作成できます。これは正確にはあなたが望んでいることではありませんが、時にはそれが役立つことがあります。たとえば(これは実際に機能します=)):

    class Program {
    static void Main(string[] args) {
        A someClass = new A();
        someClass.SomeEvent += delegate(object sender, EventArgs e) {
            throw new NotImplementedException();
        };

        someClass.ClearEventHandlers();
        someClass.FireEvent();

        Console.WriteLine("No error.");
    }

    public class A {
        public event EventHandler SomeEvent;

        public void ClearEventHandlers() {
            Delegate[] delegates = SomeEvent.GetInvocationList();
            foreach (Delegate delegate in delegates) {
                SomeEvent -= (EventHandler) delegate;
            }
        }

        public void FireEvent() {
            if (SomeEvent != null) {
                SomeEvent(null, null);
            }
        }
    }
}
6
EKazakov

匿名関数の名前が必要です。名前がスコープ内にある場合にのみ、名前を付けることができます。

    var handler = new EventHandler(delegate(object o, EventArgs e)
    {
        //do something...
    };

    Subject.NewEvent += handler;

    // later on while handler is still in scope...

    Subject.NewEvent -= handler;
2
apiguy

リーク以外の理由で登録を解除する必要がありますか?

「または単にメモリのリークを許可する」ビットに関しては、サブジェクトがガベージコレクタによってクリーンアップされるときに、匿名のデリゲートもクリーンアップされる必要があるため、リークが発生することはありません。

0
Walt W

これにいくらか(多すぎる)詳細に入る(私の)別の質問があります: ラムダで使用するための弱いイベントハンドラモデル

しかし、 ReactiveFramework が出てきたので、このような状況で真剣に検討したいと思います。

0
Benjol