Как очистить подписки на события в C#?
принять следующие в C# класс:
c1 {
event EventHandler someEvent;
}
если есть много подписок на c1
' s someEvent
событие, и я хочу очистить их все, каков наилучший способ достичь этого? также учтите, что подписки на это событие могут быть / являются лямбда / анонимными делегатами.
в настоящее время мое решение-добавить ResetSubscriptions()
метод c1
устанавливает, что someEvent
до null. Я не знаю, есть ли у этого какие-то невидимые последствия.
9 ответов
из класса вы можете установить (скрытую) переменную в значение null. Нулевая ссылка-это канонический способ эффективного представления пустого списка вызовов.
из-за пределов класса вы не можете этого сделать-события в основном выставляют "подписаться" и "отменить подписку", и все.
стоит знать, что на самом деле делают полевые события-они создают переменную и событие в то же время. В классе ты заканчиваешь ссылка на переменную. Извне вы ссылаетесь на событие.
посмотреть мои статья о мероприятиях и делегатах для получения дополнительной информации.
добавьте метод в c1, который установит 'someEvent' в null...
class c1
{
event EventHandler someEvent;
ResetSubscriptions() {someEvent = null;}
}
class c1
{
event EventHandler someEvent;
ResetSubscriptions() {someEvent = delegate{};}
}
лучше использовать delegate{} чем null
установка события в null внутри класса работает. Когда вы размещаете класс, вы всегда должны установить событие в null, GC имеет проблемы с событиями и не может очистить размещенный класс, если у него есть болтающиеся события.
для очистки всех подписчиков рекомендуется установить значение someEvent в null, добавив другой общедоступный метод, если вы хотите предоставить эту функцию извне. Это не имеет никаких невидимых последствий. Предварительное условие-не забыть объявить SomeEvent с ключевым словом "event".
пожалуйста, смотрите книгу-C# 4.0 в двух словах, стр. 125.
кто-то здесь предложил использовать Delegate.RemoveAll
метод. Если вы используете его, пример кода может следовать приведенной ниже форме. Но это действительно глупый. Почему не просто SomeEvent=null
внутри ?
public void ClearSubscribers ()
{
SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent);// Then you will find SomeEvent is set to null.
}
концептуальный расширенный скучный комментарий.
Я предпочитаю использовать слово "обработчик событий" вместо "событие" или "делегат". И использовал слово "событие" для других вещей. На некоторых языках программирования (VB.NET, Object Pascal, Objective-C)," событие "называется" сообщением "или" сигналом "и даже имеет ключевое слово" message " и конкретный синтаксис сахара.
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;
и, чтобы ответить на это "сообщение", "обработчик событий" отвечает, является ли один делегат или несколько делегатов.
резюме: "Событие" - это" вопрос"," обработчик (ы) событий " - это ответ (ы).
Это мое решение:
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()){/*...*/}
шаблон для отмены подписки на все члены списка вызовов.
удалить все события, предположим, что событие является типом "действие":
Delegate[] dary = TermCheckScore.GetInvocationList();
if ( dary != null )
{
foreach ( Delegate del in dary )
{
TermCheckScore -= ( Action ) del;
}
}