当前位置: 首页 > 编程语言 > C#

在孤立之前是否需要从对象中删除事件订阅?分享

时间:2023-04-10 15:30:58 C#

我需要在孤立之前从对象中删除事件订阅吗?如果我的软件有两个对象实例,一个订阅另一个的事件。我是否需要在它们成为孤儿之前取消订阅它们以便被垃圾收集器清理?或者,有什么其他原因我应该清除事件关系吗?如果订阅的对象是孤立的但订阅者不是孤立的,反之亦然怎么办?是的,你是。事件发布者持有对对象的引用并防止它们被垃圾收集。让我们看一个例子,看看会发生什么。我们有两个班级;一个公开事件,另一个使用事件:classClassA{publiceventEventHandlerTest;~ClassA(){Console.WriteLine("A被收集");}}classClassB{publicClassB(ClassAinstance){instance.Test+=newEventHandler(instance_Test);}~ClassB(){Console.WriteLine("B被收集");}voidinstance_Test(objectsender,EventArgse){//这个空间是有意留空的}}注意ClassB如何不存储对ClassA实例的引用;它只是连接了一个事件处理程序。现在,让我们看看如何收集对象。场景一:ClassBtemp=newClassB(newClassA());Console.WriteLine("收集1");GC.收集();控制台.ReadKey();温度=空;Console.WriteLine("收集2");GC.收集();控制台.ReadKey();我们创建了一个ClassB的实例,并通过temp变量保存了对它的引用。它传递了一个新的ClassA实例,我们没有在任何地方存储对它的引用,所以一旦ClassB构造函数完成它就会超出范围。我们在ClassA超出范围时运行一次垃圾收集器,在ClassB超出范围时运行一次。输出:Collect1A正在收集Collect2B正在收集场景2:ClassAtemp=newClassA();ClassBtemp2=newClassB(temp);临时2=空;Console.WriteLine("收集1");GC.收集();控制台.ReadKey();温度=空;Console.WriteLine("收集2");GC.收集();控制台.ReadKey();创建ClassA的新实例并将对它的引用存储在临时变量中。然后创建一个新的ClassB实例,将TempA中的ClassA实例传递给它,并在temp2中存储对它的引用。然后我们将temp2设置为null,使ClassB实例超出范围。和以前一样,我们在每个实例超出范围后运行垃圾收集器。输出:Collect1Collect2BbeingcollectedAbeingcollectedSo,总结;如果暴露事件的实例超出范围,则它可用于垃圾回收,无论是否附加了事件处理程序。如果具有事件处理程序的实例附加到另一个实例中的事件,则在事件处理程序分离或附加事件处理程序的实例可用于垃圾回收之前,它将不可用于垃圾回收。如果暴露事件的对象是长期存在的,但挂钩事件的对象是短暂存在的(并且垃圾收集速度相当快),您只需要取消挂钩事件。在这种情况下,不unhooking将导致内存泄漏,因为您的短期对象将无法进行GC-因为长期对象中的事件保留在持有短期对象的委托中。由于短代对象仍然被这个代理引用,它们不能被垃圾回收。根据定义,静态事件是长期存在的——它们会持续到程序退出。如果你挂钩一个静态事件,你一定要在完成后取消它。如果两个对象即将成为孤立对象,则无需断开连接。订阅事件会导致对订阅者的强引用。这是因为,在幕后,事件是委托,而实例方法委托是对象引用和实际方法的组合。如果您不取消订阅,发布者将继续维护引用,只要发布者还活着,订阅对象就永远不会被孤立(和GC)。反之亦然,即订阅对象没有对发布者的任何引用。以上是C#学习教程:孤儿化之前需要去掉对象的事件订阅吗?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: