Может ли прослушиватель событий WeakEvent быть удален сборщиком мусора в любое время?

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

sealed class EventWrapper
{
    SourceObject eventSource;
    WeakReference wr;
    public EventWrapper(SourceObject eventSource,
                        ListenerObject obj) {
        this.eventSource = eventSource;
        this.wr = new WeakReference(obj);
        eventSource.Event += OnEvent;
   }
   void OnEvent(object sender, EventArgs e)
   {
        ListenerObject obj = (ListenerObject)wr.Target;
        if (obj != null)
            obj.OnEvent(sender, e);
        else
            Deregister();
    }
    public void Deregister()
    {
        eventSource.Event -= OnEvent;
    }
}

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

Мой вопрос: возможно ли, что при использовании этого шаблона сборщик мусора удаляет ListenerObject obj хотя источник события заранее не вызвал событие? В этом случае весь шаблон становится неопределенным, так как сработавшее событие не пересылается WeakReference ListenerObject , поскольку сборщик мусора удалил его (поскольку на WeakReference указывает только WeakReference ). Если это правильно, почему я все равно должен использовать такой шаблон?

Спасибо

Всего 1 ответ


Да, если WeakReference является единственной вещью, которая содержит ссылку на ListenerObject , тогда ListenerObject может быть GC'd в любой точке.

Вы бы использовали шаблон, подобный этому, если ваш класс EventWrapper - не единственная вещь, которая имеет ссылку на ListenerObject , но ваш EventWrapper не знает, когда эта другая вещь выпустит свою ссылку на ListenerObject .

Например, ListenerObject может быть элементом управления UI, который появляется на экране, а EventWrapper может принадлежать одноэлементной службе. Элемент управления пользовательского интерфейса будет оставаться активным до тех пор, пока отображается этот экран, но будет освобожден, когда пользователь изменит экран. Служба может не знать, когда это произойдет. Использование шаблона слабых событий означает, что в этом случае вы случайно не получите утечку памяти.


Обратите внимание: если вы хотите реализовать шаблон слабых событий, используйте WeakEventManager как подробно описано в этой статье .