gpt4 book ai didi

c# - 在对象成为孤立对象之前,我是否需要从对象中删除事件订阅?

转载 作者:太空宇宙 更新时间:2023-11-03 15:55:43 25 4
gpt4 key购买 nike

如果我的软件有两个对象实例,其中一个订阅了另一个的事件。我是否需要在它们成为孤立对象以供垃圾收集器清理之前取消订阅它们?还是有其他原因我应该清除事件关系?如果订阅的对象是孤立的但订阅者不是孤立的,反之亦然怎么办?

最佳答案

是的,你知道。事件发布者持有对对象的引用,并会阻止它们被垃圾回收。

让我们看一个例子,看看会发生什么。我们有两个类(class);一个公开一个事件,另一个使用它:

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 实例并通过临时变量保存对它的引用。它获得了一个新的 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 实例,并将对它的引用存储在临时变量中。然后创建一个新的 ClassB 实例,将 temp 中的 ClassA 实例传递给它,我们将对它的引用存储在 temp2 中。然后我们将 temp2 设置为 null,使 ClassB 实例超出范围。和以前一样,我们让垃圾收集器在每个实例超出范围后运行。输出:

Collect 1
Collect 2
B being collected
A being collected

所以,总结一下;如果暴露事件的实例超出范围,它就可用于垃圾回收,无论是否有事件处理程序连接。如果一个实例的事件处理程序连接到另一个实例中的事件,则在事件处理程序分离或事件处理程序所附加的实例可用于垃圾回收之前,它将无法用于垃圾回收。

关于c# - 在对象成为孤立对象之前,我是否需要从对象中删除事件订阅?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23743548/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com