Как я могу очистить подписки на события в С#?
Возьмите следующий класс С#:
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;
}
}