2013-09-17 3 views
1

В WinForms я могу использовать реализацию IDisposable для отмены подписки на события формы (например: Activated, Load, ContextMenuChanged, ....), чтобы помочь сборку мусора?отписаться от событий


отподписывании в MSDN

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

+0

определенно, удалив объект, удалите все подписки, то есть предполагается, что он является IDisposable. –

ответ

3

Да, вы можете, но если обработчик событий определен в вашем собственном классе, а также определен в том же экземпляре, то вам не нужно отписываться от события, поскольку издатель и подписчик являются одним и тем же объектом. Поэтому никаких дополнительных объектов в ссылке не содержится.

Если вы подписались объект А для обработки событий от объекта В, то является стоит отказаться от события в объекте B. В противном случае групповой делегат, который лежит событие будет держать ссылки на оба объекта. И что будет предотвратить сборщик мусора от сбора обоих объектов.

+1

@Groo Thanx. Я не знал, что это было эмпирическое правило, но это просто мой собственный опыт в этом вопросе. – Maarten

4

Да, вы можете, однако, в зависимости от того, сколько событий есть, я бы сказал, что это попадет под категорию микро-оптимизации.

+2

Я бы не сказал, что это имеет какое-то отношение к производительности. Оставляя прикрепленный обработчик, предотвращает сбор родительского объекта прикрепленного метода. Вам не нужно отвлекаться от своих событий (но в большинстве случаев вы даже не должны прикрепляться к ним, а вместо этого переопределять методы OnXXX), но если вы работаете с событиями других объектов, важно отказаться от подписки, когда вы закончат их обработку. – Groo

1

Чтобы добавить @Maarten's answer, вместо обработки «собственное» события внутри Form, это, как правило, гораздо проще переопределить любого из многочисленных protected virtual методов, которые ссылаются на эти события.

I.e. вместо присоединения к Load событию:

this.Load += DoStuff; 

private void DoStuff(object sender, EventArgs e) 
{ 
    // do stuff 
} 

вы должны просто переопределить метод OnLoad, устраняя необходимость думать о отписке вообще:

protected override void OnLoad(EventArgs e) 
{ 
    // do stuff 
    ... 

    // call the base method to fire the event 
    // for external listeners 
    base.OnLoad(e); 
} 

Это оставляет вас с обработчиками только внешних объектами события, которые следует отделить, когда вы закончите использовать их.

Это также является хорошей практикой всегда иметь метод protected virtual OnXXXX для каждого из ваших открытых событий: позволить производным классам запускать событие и добавлять дополнительную логику обработки перед его выполнением.

1

В обычном случае использования WinForms издатели и подписчики соединяются и одновременно располагаются. Подписка на кнопки OnClick-событие обычно представляет собой метод класса окна, который содержит кнопку. Было бы бессмысленно удалять окно из памяти, не удаляя также кнопку.

В этих случаях вам не нужно отписываться (насколько я могу судить).

Это имеет значение только в том случае, если ваши классы подписчиков удалены до того, как издатель делает это, например. другое окно реагирует на OnLoad окна. Тогда использование IDisposable было бы хорошей идеей.

Смежные вопросы