我是否必须在终结器中删除eventHandlers?

时间:2012-04-16 15:52:16

标签: c# wpf

我有一个有Saved事件的模型类。这个想法是,如果两个视图模型使用该模型对象,如果其中一个更改它,则另一个将更新。

当我不再使用其视图模型时,是否必须删除事件处理程序?这是我的代码:

protected AbstractEntityViewModel(AbstractEntity ae)
{
    this.ae = ae;

    ae.Saved += delegate(object o, EventArgs e) 
    { 
        base.OnPropertyChanged(null);
    };
}

这没关系,还是我需要更改它以便在不再使用viewmodel时我可以-=删除委托?

3 个答案:

答案 0 :(得分:3)

它的长短是肯定的。如果AbstractEntity对象仍然具有对它的引用,则不能处理辅助对象。如果有可能放置对象并且事件仍然存在(这也适用于静态事件),那么您需要手动删除事件处理程序或者不会丢弃该对象。

答案 1 :(得分:1)

事件可以是一个原始的观察者实现:主体为每个订阅的观察者保留一个处理程序,这意味着它们无法被垃圾收集。为了允许观察者被垃圾收集,必须将其作为观察者从主体中移除。

事件处理程序不需要手动删除的唯一时间是主题和观察者是同一个实例,因为垃圾收集器将检测循环引用并随后完成对象。

答案 2 :(得分:0)

事件方向参考

要知道您是否真的需要分离事件处理程序,您首先必须了解:

ae.Saved += delegate(object o, EventArgs e) 
{ 
    base.OnPropertyChanged(null);
};

表示ae现在引用this。因此,事件的对象是使用事件处理程序引用对象。它不是相反的方式(事件处理程序引用事件)。

可以收集GC根未引用的对象

此外,理想情况下,垃圾收集的对象不会被任何其他对象引用,但这并非绝对必要:

垃圾收集器可以以任何方式(路径)收集GC根未引用的所有对象。这意味着如果你有一个对象的孤立图(引用图的其他对象的对象,但是图中没有引用图中对象的对象[也没有GC根]),那么整个对象图最终将被垃圾收集。图表交织得越多,GC收集它的成本就越高。分离事件处理程序有助于更快地解散这些图形。

正确清理物体

.Net没有Destructors功能。相反,有IDisposable模式和终结器(请参阅Implementing Finalize and Dispose to Clean Up Unmanaged Resources)。

长话短说:

  • 当对象管理非托管资源时,需要完成方法(~Foo () { }的{​​{1}})。当GC收集对象时,垃圾收集器会调用它们。所以确切的时刻不取决于你。
  • 可以使用一次性模式来清理托管和非托管资源。如果对象具有非托管资源,则它仍必须具有终结器。为什么?您调用class Foo方法。无法保证它被执行。如果应用程序无法调用Dispose()方法,那么仍然会调用最终确定的GC。所以基本上在Dispose中进行非托管资源清理只是一种性能改进(在某些情况下,这可能非常重要,除非你想在计算机中插入几兆字节的RAM ......)。

如果您打算使用终结器,我绝对敦促您阅读其中的文档,因为我在这里没有介绍过很多相关内容。见Implementing Finalize and Dispose to Clean Up Unmanaged Resources

你的例子

回到您的示例,在构建Dispose()后,只要您传递给AbstractEntityViewModel的{​​{1}}保持活着,它就会保持活力反之亦然。 但是当这两个都没有被GC根引用时,它们都被垃圾收集。

如果分离事件处理程序,即使AbstractEntity无法,也可以对AbstractEntityViewModel(或者它的具体子类实例)进行垃圾回收。

另见:Understanding Garbage Collection in .NET


相关问题