Как отменить регистрацию анонимного обработчика событий

Скажи, если я слушаю событие:

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

Теперь, как мне отменить регистрацию этого события? Или просто позволить памяти просочиться?

7 ответов

Решение

Если вам нужно отменить регистрацию события, я рекомендую избегать анонимных делегатов для обработчика событий.

Это один из случаев, когда лучше назначить это локальному методу - вы можете просто отписаться от события.

Дайте вашему экземпляру анонимного делегата имя:

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

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

Чтобы удалить обработчик при первом вызове:

//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;

Вы можете создать метод для отмены регистрации от всех слушателей события. Это не совсем то, что вы хотите, но иногда это может быть полезно. Например (это действительно работает =)):

    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);
            }
        }
    }
}

Вам нужно имя для вашей анонимной функции, а затем вы можете сделать это только в том случае, если имя находится в области видимости:

    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;

Есть еще один (мой) вопрос, который затрагивает это в некоторых (слишком много) деталях: слабая модель обработчика событий для использования с лямбдами.

Однако теперь, когда появилась Reactive Framework, я бы серьезно подумал об этом в такой ситуации.

Вам нужно отменить регистрацию по какой-либо причине, кроме утечки?

Что касается бита "Или просто позволить утечке памяти", то, когда Subject очищается сборщиком мусора, ваш анонимный делегат также должен быть очищен, чтобы не было утечки.

Другие вопросы по тегам