Быстрое разъяснение о том, когда мне нужно удалить обработчики в .Net, VB.Net - PullRequest
2 голосов
/ 06 августа 2010

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

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

ETA: Вот ситуация, когда я думаю, что мне нужно удалить обработчики. Пожалуйста, поправьте меня, если я ошибаюсь.

У меня есть коллекция; каждый раз, когда объект добавляется в эту коллекцию, я добавляю обработчик к событию изменения объекта. Когда я закончу с коллекцией, мне нужно пройти через каждый элемент и удалить обработчик перед установкой ссылки на ноль?

Ответы [ 3 ]

3 голосов
/ 06 августа 2010

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

Например ...

public class LostInLimbo
{
  private Villain _problem;

  public void SetVillain(Villain problem)
  {
    problem.SomeEvent += this.SomeHandler;
    _problem = problem;
  }
}

Учитывая этот класс, если мы сделаем следующее:

Villain foo = new Villain();
LostInLimbo victim = new LostInLimbo();
victim.SetVillain(foo);
victim = null;

экземпляр victim теперь "просочился".На него ссылается foo и, следовательно, он не будет собран;однако вы не можете получить доступ к этому экземпляру.Сделайте это несколько сотен тысяч раз, и у вас может возникнуть проблема.

В этом случае вы бы хотели, чтобы LostInLimbo реализовал IDisposable, где вы можете отцепить событие:

var temp = _problem;
_problem = null;
if (temp != null_
  temp -= this.SomeHandler;

Аналогично,Вы можете получить утечку, если сделаете это:

public class LostInLimbo
{
  public Villain Problem {get;private set;}

  public LostInLimbo()
  {
    Problem = new Villain();
    Problem.SomeEvent += this.SomeHandler;
  }
}

и выполните следующую

var temp = new LostInLimbo().Villain;

Та же ситуация.Злодей держит ссылку на экземпляр LostInLimbo, но у вас нет доступа к этому экземпляру.Опять же, реализация IDisposable позволит экземпляру LostInLimbo отсоединиться.Конечно, есть и другие проблемы с этим, но это всего лишь пример.

Если, однако, у вас есть такая ситуация:

public class LostInLimbo
{
  private Villain _problem;
  public LostInLimbo()
  {
    _problem = new Villain();
    _problem.SomeEvent += this.SomeHandler;
  }
}

Нет проблем.Только LostInLimbo содержит ссылку на _problem, а _problem не содержит ссылок ни на один экземпляр LostInLimbo, кроме того, который «владеет» им.После того, как этот экземпляр собран, так же и _problem.


В ответ на ваше обновление я сделаю следующее.

Сначала, когда элемент добавляется в коллекцию, коллекция подключается к элементу (переопределяет любой метод, добавляющий элемент в коллекцию).Когда элемент удаляется из коллекции, коллекция отсоединяется от элемента (опять же, переопределите любой метод, который удаляет элемент из коллекции).Я бы также реализовал IDisposable для очистки коллекции при утилизации.Я хотел бы убедиться, что любой тип, который использовал коллекцию, также реализует IDisposable.

1 голос
/ 06 августа 2010

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

Однако, если источник события всегда перевешивает потребителя, у вас есть проблема. Вам понадобится какой-то триггер для отмены регистрации обработчика событий. Если потребитель уже реализует Dispose (), тогда это может быть место для отмены регистрации обработчика. Если нет, то вам следует рассмотреть возможность использования простого метода обратного вызова вместо события.

1 голос
/ 06 августа 2010

Это действительно зависит -

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...