2010-03-28 3 views
12

Есть ли простой способ перебора всех обработчиков, подписанных на данное событие? Моя проблема заключается в том, что клиенты подписываются, но забывают отказаться от подписки, так что происходит утечка памяти. Мне нужен способ для объекта отключить все обработчики его событий в методе Dispose, чтобы утечка не произошла - по крайней мере, не из-за событий.C# Как отменить подписку на все обработчики событий из данного события?

ответ

11

Установить нуль на мероприятие: MyEvent = null;

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

+1

Это не представляется возможным установить событие NULL, в C#. –

+8

На самом деле это возможно, если вы находитесь внутри класса, где было объявлено событие. –

+1

Вы правы. –

9

Альтернативный подход заключается в использовании так называемого «слабого делегата». Когда вы используете этот метод, событие ссылается на клиентов только с использованием WeakReference, который не сохраняет их в памяти. Клиенты будут собирать мусор, когда они больше не ссылаются на другую часть приложения (и обработчик также может быть незарегистрирован автоматически при получении клиента).

Это обычно используется для решения проблемы с «забыванием» клиентов, чтобы отказаться от подписки на событие .NET, поэтому кажется, что это может быть хорошо подходит для вашей проблемы.

  • Dusing Campbell имеет хороший article about weak delegates.
  • Мне тоже понравилось overview at CodeProject, в котором обсуждается большинство сценариев.
  • Weak Events также используются в WPF, но этот подход кажется немного сложным (для меня).
7

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

Если источник события умирает перед слушателем, это не мешает прослушиванию слушателя позже, когда все остальные ссылки на него установлены в нуль.

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

1

На момент написания статьи наиболее точный ответ наименее популярен.

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

Исходный класс Ади позволит собирать объекты для прослушивания, когда он сам собран, нет сомнений. Таким образом, проблема заключается в том, что исходный объект Adi остается открытым, возможно, из некоторой длинной цепочки ссылок в коде клиента.

Следующее сообщение в блоге также рассматривает решение, которое Adi описывает и объясняет, почему это не нужно.

http://weblogs.sqlteam.com/mladenp/archive/2007/10/24/C-Care-about-Event-Memory-Leaks-with-Delegate.GetInvocationList.aspx

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