Управление подпиской на обработчик событий C #

#c# #event-handling

#c# #обработка событий

Вопрос:

У меня есть класс:

 public abstract class BaseComponent { ... }
  

Внутри конструктора этого класса мы подписываемся на обработчик событий, например

 protected ObjectWithEventHandler eventObject { get; private set; }

public BaseComponent (ObjectWithEventHandler obj)
{
    eventObject = obj;
    eventObject.ChangedEvent  = new EventHandler(eventObject_OnChangedEvent );
}

protected void eventObject_OnChangedEvent (object sender, EventArgs e) { ... }
  

Существуют ли какие-либо жесткие и быстрые правила, когда дело доходит до подписки и отмены подписки на EventHandler?

Считается ли хорошей практикой предоставлять некоторый код очистки, который отменяет подписку на функцию от обработчика событий? Т.е. Реализовать IDisposable и затем отказаться от подписки от обработчика событий?

Или я излишне беспокоюсь?

Комментарии:

1. Я почти уверен, что вам не нужно беспокоиться об этом. C # должен очищать любые ссылки на события, когда ваш экземпляр получает сбор мусора (т. Е. Больше Не находится в области видимости или На экземпляр больше нигде не ссылаются)

2. @musefan, история немного сложнее: вам нужно учитывать время жизни задействованных объектов.

Ответ №1:

Если у вас есть полный контроль над использованием BaseComponent и вы знаете, что жизненный цикл EventObject короче или равен * в отношении жизненного цикла BaseComponent , вы можете пропустить код отмены подписки.

Во всех остальных случаях я бы включил его. В этом случае реализация IDisposable является хорошим стилем.

*) по сути, вы связываете время жизни EventObject с BaseComponent, поэтому оно не может быть короче, но оно все равно может быть равным, когда оба выходят за рамки вместе.

Ответ №2:

Пока объект, который предоставляет event ( eventObject ), создается внутри BaseComponent класса, вы можете игнорировать явную отмену подписки, потому что она будет GCed автоматически, но явная отмена подписки в любом случае является хорошей практикой.

Но если вы подписываетесь на событие, которое передается внешним объектом, введенным в BaseComponent вас, вы должны реализовать IDisposable в BaseComponent классе и в Dispose() методе do cleanup.

Ответ №3:

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

Реализация IDisposable() — хороший способ добиться этого, если вы можете быть уверены, что на самом деле существует какой-то код, вызывающий его. Завершитель не будет вызывать Dispose() , потому что сборщик мусора не будет пытаться очистить ваш компонент, пока он подписан на EventObject .ChangedEvent и EventObject все еще работают.