代码之家  ›  专栏  ›  技术社区  ›  Sean

我需要处理以注销事件吗?[复制品]

  •  5
  • Sean  · 技术社区  · 14 年前

    这个问题已经有了答案:

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

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

    如果a从未从b的事件中注销,那么a将不会被垃圾回收吗?a需要dispose方法来从b的事件中注销吗?

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

    3 回复  |  直到 13 年前
        1
  •  4
  •   flq    14 年前

    对于你的第一个问题:是的。B有对A的引用。这样A的寿命就和B一样长。这是一个很好的方式来释放UI应用程序中的内存,如果你注册了像app.onidle这样的事件。

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

        2
  •  1
  •   supercat    13 年前

    正如您所怀疑的,断开事件连接的正确位置是 IDisposable.Dispose 方法 A . 没有什么好的选择。尝试在内部断开事件连接是没有用的 的终结器/析构函数,因为 在断开与 B 将是 使自己有资格进行垃圾收集;一旦发生这种情况,订阅将成为一个没有意义的点,因此不管它是否被清理干净。

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

        3
  •  0
  •   kemiller2002    14 年前

    如果B持有对A的引用,则除非B也有资格进行垃圾收集,否则A不会得到垃圾收集。

    你不应该需要一个处理方法。一旦b也没有指向它的引用,垃圾收集器就足够聪明,可以同时处理b和a。

    如果它们在应用程序的生命周期内都是活动的,则不需要注销事件。