Как я могу очистить подписки на события в С#?

Возьмите следующий класс С#:

c1 {
 event EventHandler someEvent;
}

Если есть много подписчиков на событие c1 someEvent, и я хочу их очистить, что лучший способ достичь этого? Также обратите внимание, что подписки на это событие могут быть/являются lambdas/анонимными делегатами.

В настоящее время мое решение заключается в добавлении метода ResetSubscriptions() к c1, который устанавливает someEvent в null. Я не знаю, имеет ли это какие-либо невидимые последствия.

Ответ 1

Внутри класса вы можете установить (скрытую) переменную в значение null. Нулевая ссылка - это канонический способ представления пустого списка вызовов.

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

Стоит осознавать, какие именно события на самом деле делают - они одновременно создают переменную и событие. Внутри класса вы в конечном итоге ссылаетесь на переменную. Со стороны вы ссылаетесь на событие.

Дополнительную информацию см. в статье о событиях и делегатах.

Ответ 2

Добавьте метод в c1, который установит 'someEvent' в null...

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

Ответ 3

Лучшая практика для очистки всех подписчиков - установить для someEvent значение null путем добавления другого общедоступного метода, если вы хотите открыть эту функцию снаружи. Это не имеет никаких очевидных последствий. Предварительным условием является запоминание объявления SomeEvent с ключевым словом "event".

См. книгу - С# 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.
    }

Ответ 4

class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = delegate{};}
}

Лучше использовать делегат {}, чем null

Ответ 5

Это можно сделать с помощью методов Delegate.Remove или Delegate.RemoveAll.

Ответ 6

Установка события в значение null внутри класса. Когда вы размещаете класс, вы всегда должны устанавливать событие равным нулю, GC имеет проблемы с событиями и может не очищать выделенный класс, если он имеет свисающие события.

Ответ 7

Концептуальный расширенный скучный комментарий.

Я скорее использую слово "обработчик событий" вместо "event" или "delegate". И использовал слово "событие" для других вещей. В некоторых языках программирования (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;

И, чтобы ответить на это "сообщение", "обработчик событий" отвечает, является ли один делегат или несколько делегатов.

Резюме: "Событие" - это "вопрос", "обработчик событий" - это ответ (ы).

Ответ 8

Удалите все события, предположим, что это событие "Тип действия":

Delegate[] dary = TermCheckScore.GetInvocationList();

if ( dary != null )
{
    foreach ( Delegate del in dary )
    {
        TermCheckScore -= ( Action ) del;
    }
}