C# 是否必须删除终结器中的EventHandler?
我有一个模型类,它保存了一个C# 是否必须删除终结器中的EventHandler?,c#,wpf,C#,Wpf,我有一个模型类,它保存了一个事件。其思想是,如果两个ViewModel使用该模型对象,如果其中一个更改了该对象,则另一个将被更新 当我不再使用事件处理程序的视图模型时,是否必须删除它?这是我的密码: protected AbstractEntityViewModel(AbstractEntity ae) { this.ae = ae; ae.Saved += delegate(object o, EventArgs e) { base.OnPrope
事件。其思想是,如果两个ViewModel使用该模型对象,如果其中一个更改了该对象,则另一个将被更新
当我不再使用事件处理程序的视图模型时,是否必须删除它?这是我的密码:
protected AbstractEntityViewModel(AbstractEntity ae)
{
this.ae = ae;
ae.Saved += delegate(object o, EventArgs e)
{
base.OnPropertyChanged(null);
};
}
这可以吗,还是我需要更改此选项,以便在不再使用viewmodel时可以-=
删除代理?Long and short of it Is yes。如果AbstractEntity对象仍有对其的引用,则无法处理次对象。如果对象有可能被释放,而事件仍然存在(对于静态事件也是如此),那么您需要手动删除eventhandler,否则对象将不会被释放。事件可以被视为原始观察者实现:主体保留每个订阅观察者的处理程序,这意味着它们无法被垃圾收集。要允许对观察者进行垃圾收集,必须将其作为观察者从主题中移除
事件处理程序不需要手动删除的唯一时间是当主体和观察者是同一实例时,因为垃圾收集器将检测循环引用并随后确定对象。事件引用的方向
要知道是否真的需要分离事件处理程序,首先必须了解:
ae.Saved += delegate(object o, EventArgs e)
{
base.OnPropertyChanged(null);
};
表示ae
正在引用此。因此,带有事件的对象正在引用带有事件处理程序的对象。而不是相反(事件处理程序引用事件)
可以收集GC根目录未引用的对象
此外,虽然理想情况下要进行垃圾收集的对象不会被任何其他对象引用,但这并不是严格必要的:
垃圾收集器可以以任何方式(路径)收集GC根未引用的所有对象。这意味着如果您有一个孤立的对象图(对象引用图中的其他对象,但图外没有对象引用图中的对象[也没有GC根]),那么整个对象图最终将被垃圾收集。图形越复杂,GC收集它的成本就越高。分离事件处理程序有助于更快地分解此类图
正确清理对象
.Net不具有析构函数。取而代之的是IDisposable
模式和终结器(请参阅)
长话短说:
- 当对象管理非托管资源时,需要使用终结方法(
~Foo(){}
,用于类Foo
)。垃圾收集器在GC收集对象时调用它们。所以确切的时间不取决于你
- 一次性模式可用于清理托管资源和非托管资源。如果对象具有非托管资源,则它必须仍然具有终结器。为什么?
Dispose()
方法由您调用。不能保证它会被执行。如果应用程序未能调用Dispose()
方法,则仍有GC调用finalize。因此,在Dispose中执行非托管资源清理基本上只是一种性能改进(在某些情况下,这可能非常重要,除非您想在计算机中插入更多的GB RAM…)
如果你打算使用终结器,我绝对建议你阅读它上面的文档,因为有很多东西我没有在这里介绍。看
你的榜样
回到您的示例,在构建AbstractEntityViewModel
之后,只要传递给AbstractEntity ViewModel
的AbstractEntity
保持活动状态,它就会保持活动状态,反之亦然。
但当这两个都没有被GC根引用时,它们都会被垃圾收集
如果分离事件处理程序,即使抽象实体
不能,也可以垃圾收集抽象实体ViewModel
(或者更确切地说,它是具体的子类实例)
另见:
如果仍然存在对对象的引用,它将永远无法执行终结器-您必须在其他地方执行此操作,例如Dispose
方法。@BrokenGlass那么这是如何工作的-我实现IDisposable
并删除OnDispose
中的事件处理程序?那之后我还要做什么吗?