C # Как отписаться от всех обработчиков событий для данного события? - PullRequest
13 голосов
/ 28 марта 2010

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

Ответы [ 4 ]

12 голосов
/ 28 марта 2010

Установить ноль для вашего события: MyEvent = null;

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

9 голосов
/ 28 марта 2010

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

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

7 голосов
/ 28 марта 2010

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

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

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

1 голос
/ 02 апреля 2010

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

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

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

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

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

...