C# 是否需要删除析构函数中的事件处理程序?
我使用一些C# 是否需要删除析构函数中的事件处理程序?,c#,wpf,events,event-handling,destructor,C#,Wpf,Events,Event Handling,Destructor,我使用一些UserControls,它们在运行时在我的应用程序中被创建和销毁(通过创建和关闭包含这些控件的子窗口)。 它是一个WPF用户控件,继承自System.Windows.Controls.UserControl。没有我可以覆盖的Dispose()方法。 PPMM是一个与我的应用程序具有相同生命周期的Singleton。 现在,在我的(WPF)UserControl的构造函数中,我添加了一个事件处理程序: public MyControl() { InitializeCompone
UserControls
,它们在运行时在我的应用程序中被创建和销毁(通过创建和关闭包含这些控件的子窗口)。它是一个WPF用户控件,继承自
System.Windows.Controls.UserControl
。没有我可以覆盖的Dispose()
方法。PPMM
是一个与我的应用程序具有相同生命周期的Singleton
。现在,在我的(WPF)
UserControl
的构造函数中,我添加了一个事件处理程序:
public MyControl()
{
InitializeComponent();
// hook up to an event
PPMM.FactorChanged += new ppmmEventHandler(PPMM_FactorChanged);
}
我习惯于在析构函数中删除此类事件处理程序:
~MyControl()
{
// hook off of the event
PPMM.FactorChanged -= new ppmmEventHandler(PPMM_FactorChanged);
}
今天,我偶然发现了这一点,并想知道:
1)这是必要的吗?还是由总承包商负责?
2)这是否有效?或者我必须存储新创建的ppmmEventHandler
?
我期待着你的回答。如果代码到达析构函数,那就不重要了 这是因为它只有在不再收听任何事件时才会被销毁。
如果它仍然在监听事件,它就不会被销毁。因为
PPMM
是一个长寿命的对象(singleton),那么这个代码就没有什么意义了
这里的问题是,只要该事件处理程序引用该对象,它就没有资格进行垃圾收集,至少只要拥有该事件的另一个对象处于活动状态
因此,将任何内容放入析构函数都是毫无意义的,因为:
IDisposable
时,可以对向Dispose
方法添加这样的代码提出不同的观点。在这种情况下,它完全有意义,因为它的用户代码在预定义的受控点调用Dispose
但是,只有当对象符合垃圾收集条件并且具有终结器时,才会调用终结器(析构函数),在这种情况下没有意义
至于问题nbr。2,我把它理解为“我可以取消订阅这样的活动吗”,那么是的,你可以。只有在围绕匿名方法或lambda表达式构造委托时,才需要保留用于订阅的委托。当您围绕现有方法构建它时,它将起作用
编辑:WPF。对,没看到那个标签。对不起,我其余的回答对WPF没有多大意义,因为我不是WPF大师,我真的不能说。然而,有一种方法可以解决这个问题。这是完全合法的,所以如果你能改进的话,就把另一个答案的内容挖出来。因此,如果有人知道如何正确地使用WPF用户控件来实现这一点,您可以自由地阅读我的答案的整个第一部分,并添加WPF的相关部分 编辑:让我也来回答这里评论中的问题 由于所讨论的类是一个用户控件,因此它的生存期将绑定到一个窗体。当窗体关闭时,它将处理它所拥有的所有子控件,换句话说,这里已经存在一个dispose方法 如果用户控件管理自己的事件,则处理此事件的正确方法是在Dispose方法中取消钩住事件处理程序 (其余部分已移除)
首先,我要说的是,不要使用析构函数,而是Dispose()来清除资源 其次,在我看来,如果此代码位于一个经常创建且生命周期很短的对象中,那么最好自己删除事件处理程序,因为这是一个到holder对象的链接,这将阻止GC收集它 问候。2)这确实有效
1) 我有一个案例(使用应用内消息服务),事件处理程序指向未发布的全局对象,因此GC无法收集该对象。我认为这通常是一种罕见的情况——如果你认为这种情况发生在你身上,那么使用像红门蚂蚁这样的分析器,你可以轻松地进行内存分析。是不是
PPMM
比MyControl
实例寿命更长的外部工具
如果是这样,除非PPMM_FactorChanged
是一个静态方法,否则ppmmEventHandler
将保留对MyControl
实例live的引用-这意味着该实例将永远无法进行垃圾收集,并且终结器也永远不会启动
您不需要为删除代码保留
ppmmEventHandler
。GC将处理该问题。虽然事件持有强引用,但它仅在父对象本身上持有强引用。最后,只有MyControl将通过事件处理程序保留引用,因此GC将收集它
另一方面,使用终结器,它不是描述器。是因为这种坏习惯。如果你想注销一个事件,你应该考虑<代码> IDISPOSTABLE 。
事件处理程序是棘手的,并且可以很容易地隐藏资源泄漏。正如蒂格兰所说。使用IDisposeable并忘记析构函数。我建议测量一下你是否做对了。只要在task manager中查看应用程序的内存消耗情况,就可以判断是否存在泄漏,如果您通过加载并关闭数千个窗口对其进行一点压力测试
WPF不支持IDisposable
well。如果您正在实现一个需要清理的WPF控件,那么应该考虑挂接到and