В моем последнем вопросе я спросил, что может нарушить самоочищающийся блок кода, предназначенный для удаления всех подписок из поля делегатов события, когда удаляется родительский объект события.Однако мне сообщили, что установка события на null делает именно то, что я пытался сделать с соответствующим кодом, но без дополнительных циклов и строк кода.
Эта статья демонстрирует, что установка события на ноль (очистка поля делегата) не гарантирует, что его ничего не слушает, и что даже если событие установлено на ноль, оно можетвсе еще держаться от сборщика мусора.
Итак, вопрос в том, есть ли способ для издателя отписаться от своих слушателей?
-
Что касается контекста, я знаю, что слушатель, как правило, должен удалить свою собственную подписку, когда он завершит прослушивание, но я хотел бы немного большей уверенности, чем это, есливозможный.Кроме того, мне иногда приходится иметь дело с кодом, в котором я не совсем уверен, все ли слушатели отписались, когда издатель был ликвидирован.
В случае, если это актуально, код из моего последнего вопроса выглядит следующим образом:
public event CustomEventHandler customHandler;
...
///During this object's lifetime, some other object subscribes to this event.
...
///Method used for cleanup
void ClearSubscriptions(CustomEventHandler handler){
if(handler == null){return;}
Delegate[] delegates = handler.GetInvocationList();
foreach(Delegate item in delegates){
handler -= (CustomEventHandler)item;
}
}
Это очищает список делегатов события, но мне сказали, что установка customHandler = null должнаделать то же самое.Я также подумал, что это гарантирует, что ничто все еще не слушает / ссылается на событие, но, похоже, это не так, как объясняется ниже.
Чтобы суммировать соответствующий код в ссылочной статье, примером статьи является форма, которая позволяет пользователю генерировать объект "EventGenerator" при одном из трех различных условий:
1.) Тамнет очистки событий объекта.
2.) Издатель очищается, устанавливая событие в нуль.
3.) Слушатель очищается, отписавшись от события.
Они контролируются радиоконтролем, поэтому одновременно может быть активным только одно условие.У объекта EventGenerator есть событие, которое вызывается при его создании.Каждому EventGenerator присваивается номер, начиная с 0 и увеличивая.Форма имеет обработчик события, который подписывается на это событие, и всякий раз, когда это событие вызывается, обработчик события печатает, что был создан новый EventGenerator, вместе с номером этого объекта.Кроме того, форма ссылается только на один EventGenerator за раз, поэтому каждый раз, когда создается новый, предыдущий забывается.
В соответствии с вариантом 1, каждый раз, когда создается новый из этих объектов, все созданные объекты запускают диалог «Я был создан».Это ожидается, поскольку форма все еще подписана на все эти экземпляры, даже если они были разыменованы.
В варианте 3 при создании нового объекта форма отменяет подписку на событие предыдущего EventGenerator перед разыменованием его, поэтому отображается диалоговое окно «созданного» нового объекта, а также диалоговое окно «завершенного» старого объекта.Это показывает, что объект был собран сборщиком мусора и больше не содержит никаких ресурсов.
Вариант 2 меня смущает.Когда активна опция 2, если создается новый EventGenerator, тогда старый удаляется.Форма не отменяет подписку, но предыдущий объект устанавливает нулевое событие.Диалоговое окно «Новый объект» отображается один раз с номером нового объекта.Предыдущие генераторы молчат, что означает, что их события не запускаются, и это хорошо.Однако их «завершенный» диалог никогда не запускается.Это означает, что, хотя для события задано значение NULL, EventGenerator по-прежнему не подходит для сборки мусора, что приводит к утечке памяти.
Мне кажется, что это происходит потому, что сама форма никогда не отписывается отсобытие в опции 2. Затем, даже если событие больше не существует, форма все еще указывает на него, и это не позволяет сборщику мусора отсутствовать.
Так что в этом контексте мне любопытно.Есть ли способ для издателя события отписаться от своих слушателей и позволить Варианту 2 освободить эти разыменованные объекты?
Кроме того, извините за эту дополнительную информацию, настолько многословную!