5

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

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

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

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

这可以吗,还是我需要更改它以便-=在不再使用视图模型时摆脱委托?

4

3 回答 3

3

总而言之,是的。如果 AbstractEntity 对象仍然具有对辅助对象的引用,则不能释放辅助对象。如果有可能释放对象并且事件仍然存在(这也适用于静态事件),那么您需要手动删除事件处理程序,否则对象将不会被释放。

于 2012-04-16T16:00:27.370 回答
2

事件参考方向

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

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

手段ae现在正在引用this. 因此,带有事件的对象正在使用事件处理程序引用该对象。不是相反(事件处理程序引用事件)。

GC root 没有引用的对象可以被收集

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

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

正确清理对象

.Net 没有析构函数。取而代之的是IDisposable模式和终结器(请参阅实现终结和处置以清理非托管资源)。

长话短说:

  • 当对象管理非托管资源时,需要终结方法 ( ~Foo () { }for )。class Foo它们在 GC 收集对象时由垃圾收集器调用。所以确切的时间不取决于你。
  • 一次性模式可用于清理托管和非托管资源。如果对象有非托管资源,它仍然必须有一个终结器。为什么?该Dispose()方法由您调用。不能保证它正在执行。如果应用程序调用该Dispose()方法失败,仍然有调用 finalize 的 GC。因此,基本上在 Dispose 中进行非托管资源清理只是一种性能改进(在某些情况下,这可能非常重要,除非您想在计算机中插入更多 GB 的 RAM ......)。

如果你打算使用终结器,我强烈建议你阅读上面的文档,因为有很多东西我没有在这里介绍。请参阅实施 Finalize 和 Dispose 以清理非托管资源

你的例子

回到你的例子,在你构造 a 之后AbstractEntityViewModel,只要AbstractEntity你传递给它,它就会保持活动AbstractEntityViewModel状态,反之亦然。但是当这两个都没有被 GC 根引用时,它们都会被垃圾回收。

如果分离事件处理程序,AbstractEntityViewModel即使不能,也可以对(或者更确切地说是具体的子类实例)进行垃圾收集AbstractEntity

另请参阅:了解 .NET 中的垃圾收集


于 2014-10-17T12:23:13.907 回答
1

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

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

于 2012-04-16T16:28:03.387 回答