Нужно ли удалять подписки на события из объектов, прежде чем они станут сиротами?

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

Ответы на вопрос(3)

Решение Вопроса

вы делаете. Издатели событий хранят ссылки на объекты и не позволяют собирать мусор.

вайте посмотрим на пример, чтобы увидеть, что происходит. У нас есть два класса; один выставляет событие, другой потребляет его:

class ClassA
{
    public event EventHandler Test;
    ~ClassA()
    {
        Console.WriteLine("A being collected");
    }
}
class ClassB
{
    public ClassB(ClassA instance)
    {
        instance.Test += new EventHandler(instance_Test);
    }

    ~ClassB()
    {
        Console.WriteLine("B being collected");
    }

    void instance_Test(object sender, EventArgs e)
    {
        // this space is intentionally left blank
    }
}

Обратите внимание, что ClassB не хранит ссылку на экземпляр ClassA; он просто подключает обработчик событий.

Теперь давайте посмотрим, как собраны объекты. Сценарий 1:

ClassB temp = new ClassB(new ClassA());
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();

Мы создаем экземпляр ClassB и храним ссылку на него через переменную temp. Ему передается новый экземпляр ClassA, где мы нигде не храним ссылку на него, поэтому он выходит из области видимости сразу после завершения конструктора ClassB. У нас сборщик мусора запускается один раз, когда ClassA выходит из области видимости, и один раз, когда ClassB выходит из области видимости. Выход:

Collect 1
A being collected
Collect 2
B being collected

Сценарий 2:

ClassA temp = new ClassA();
ClassB temp2 = new ClassB(temp);
temp2 = null;
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();

Создается новый экземпляр ClassA, и ссылка на него сохраняется в переменной temp. Затем создается новый экземпляр ClassB, передавая ему экземпляр ClassA в temp, и мы сохраняем ссылку на него в temp2. Затем мы устанавливаем для temp2 значение null, в результате чего экземпляр ClassB выходит из области видимости. Как и раньше, у нас запускается сборщик мусора после того, как каждый экземпляр вышел из области видимости. Выход:

Collect 1
Collect 2
B being collected
A being collected

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

но с тем, что под прикрытием события являются делегатами, а делегаты для методов экземпляра являются комбинацией ссылки на объект и фактического метода. Если вы не отмените подписку, издатель продолжит поддерживать ссылки, и объекты подписки никогда не станут по-настоящему осиротевшими (и GC 'ed), пока издатель жив.

Обратное неверно, то есть подписанный объект не имеет никакой ссылки на издателя.

exposing события долгоживущие, но объектhooking в противном случае событие было бы недолгим (и собирать мусор довольно быстро).

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

Статические события являются долгоживущими по определению - они живут до выхода из программы. Если вы перехватываете статическое событие, вам определенно следует отцепить его, когда вы закончите.

Если оба объекта становятся сиротами, отцепление не требуется.

Ваш ответ на вопрос