我是否需要处理取消注册事件?

时间:2010-04-13 14:23:54

标签: c# .net events dispose

假设我有两个类,它们都不是GUI组件。 A类是一个短期对象,它注册由长期存在的对象B声明的事件。例如

public A(B b)
{
   b.ChangeEvent += OnChangeEvent;
}

如果A从未退出B的事件,A将永远不会被垃圾收集? A是否需要Dispose方法才能取消B的事件?

还有一个相关的第二个问题。如果A和B都应该在应用程序的整个执行时间内存活,那么A是否需要取消注册?

3 个答案:

答案 0 :(得分:4)

提出第一个问题:是的。 B有一个对A的引用。这样A的存活时间与B一样长。这是一种在UI应用程序中释放内存的好方法,例如:注册App.OnIdle等事件。

到第二个:最后一切都将被杀死。

答案 1 :(得分:1)

正如您所怀疑的那样,断开事件的正确位置将采用IDisposable.Dispose A方法。没有什么好的选择。试图在A的终结器/析构函数中断开事件是没有用的,因为A在与B断开连接之前有资格进行垃圾收集的唯一方法是使B成为垃圾收集资格;一旦发生这种情况,订阅将成为一个没有实际意义的点,所以无论是否清理它都无关紧要。

如果必须在长期存在的发布者的生命周期内清除被遗弃的短期订阅者的事件,那么如果发布和订阅类合作,有很多方法可以做到这一点。例如,事件订阅者的公共面可以是包装对象,其保存对实际事件订阅者的引用,订阅者本身不持有对该公共对象的强引用。在这种情况下,事件订阅不会阻止公共对象超出范围并且有资格进行最终确定。公共对象中的终结器可以通知订阅对象不再需要订阅,并且应该取消订阅。由于这种通知将异步到达,因此发布订阅的对象必须提供一种方法,通过该方式可以异步地取消订阅订阅者。这可以通过正常的“取消订阅”请求来完成,前提是发布事件保证它是非阻塞和线程安全的;不幸的是,大多数活动都没有提供这样的保证。

答案 2 :(得分:0)

如果B持有A的引用,A将不会收集垃圾,除非B也符合垃圾收集的条件。

您不应该为此使用Dispose方法。一旦B没有指向它的引用,垃圾收集器将足够聪明地处理B和A.

如果它们在应用程序的生命周期中都存活,则无需取消注册该事件。