Когда слушатель присоединяет слушателя события к событию, исходный объект получит ссылку на объект слушателя.Это означает, что слушатель не может быть собран сборщиком мусора до тех пор, пока не будет отключен обработчик событий или не будет собран исходный объект.
Рассмотрим следующие классы:
class Source
{
public event EventHandler SomeEvent;
}
class Listener
{
public Listener(Source source)
{
// attach an event listner; this adds a reference to the
// source_SomeEvent method in this instance to the invocation list
// of SomeEvent in source
source.SomeEvent += new EventHandler(source_SomeEvent);
}
void source_SomeEvent(object sender, EventArgs e)
{
// whatever
}
}
...и затем следующий код:
Source newSource = new Source();
Listener listener = new Listener(newSource);
listener = null;
Даже если мы присвоим null
для listener
, он не будет иметь права на сборку мусора, так как newSource
все еще содержит ссылку на обработчик события (Listener.source_SomeEvent
).Чтобы устранить утечку такого рода, важно всегда отсоединять прослушиватели событий, когда они больше не нужны.
Приведенный выше пример написан для того, чтобы сосредоточиться на проблеме с утечкой.Чтобы исправить этот код, возможно, проще всего будет позволить Listener
удерживать ссылку на Source
, чтобы впоследствии он мог отсоединить прослушиватель события:
class Listener
{
private Source _source;
public Listener(Source source)
{
_source = source;
// attach an event listner; this adds a reference to the
// source_SomeEvent method in this instance to the invocation list
// of SomeEvent in source
_source.SomeEvent += source_SomeEvent;
}
void source_SomeEvent(object sender, EventArgs e)
{
// whatever
}
public void Close()
{
if (_source != null)
{
// detach event handler
_source.SomeEvent -= source_SomeEvent;
_source = null;
}
}
}
Затем вызывающий кодможет сигнализировать, что это сделано с помощью объекта, который удалит ссылку, которая Source
имеет на «Listener»;
Source newSource = new Source();
Listener listener = new Listener(newSource);
// use listener
listener.Close();
listener = null;