您是否需要在析构函数中删除事件处理程序?

Mar*_*ngs 51 c# wpf events destructor event-handling

UserControls在运行期间使用了一些在我的应用程序中创建和销毁的内容(通过创建和关闭内部带有这些控件的子窗口).
它是一个WPF UserControl并继承自System.Windows.Controls.UserControl.Dispose()我无法覆盖任何方法.
PPMM是一个Singleton具有相同的寿命为我的应用程序.
现在在我的(WPF)的构造函数中UserControl,我添加了一个事件处理程序:

public MyControl()
{
    InitializeComponent();

    // hook up to an event
    PPMM.FactorChanged += new ppmmEventHandler(PPMM_FactorChanged);
}
Run Code Online (Sandbox Code Playgroud)

我习惯在析构函数中删除这样的事件处理程序:

~MyControl()
{
    // hook off of the event
    PPMM.FactorChanged -= new ppmmEventHandler(PPMM_FactorChanged);
}
Run Code Online (Sandbox Code Playgroud)

今天我偶然发现了这件事,并想知道:

1)这是必要的吗?或者GC会照顾它吗?

2)这甚至有用吗?或者我是否必须存储新创建的ppmmEventHandler

我很期待你的回答.

ang*_*son 34

既然PPMM是一个长期存在的对象(单例),那么这段代码没有多大意义.

这里的问题是,只要该事件处理程序引用该对象,它就没有资格进行垃圾收集,至少只要拥有该事件的其他对象是活动的.

因此,在析构函数中放置任何内容都是毫无意义的,因为:

  1. 事件处理程序已被删除,因此该对象符合垃圾回收条件
  2. 不删除事件处理程序,拥有对象不符合垃圾回收的条件,因此永远不会调用终结器
  3. 这两个对象都有资格进行垃圾回收,在这种情况下,你不应该在终结器中访问那个其他对象,因为你不知道它的内部状态

总之,不要这样做.

现在,Dispose当你实现时,可以说关于在方法中添加这样的代码的另一个论点IDisposable.在这种情况下,它完全有意义,因为它的用户代码Dispose在预定义和受控点调用.

终结(析构函数),但是,只有当对象符合垃圾收集和有一个终结,在这种情况下,没有一点叫.

至于问题nbr.2,我将其视为"我能否取消订阅此类事件",然后是,您可以.您需要保留您以前订阅的委托的唯一时间是在围绕匿名方法或lambda表达式构建委托时.当您围绕现有方法构建它时,它将起作用.


编辑:WPF.对,没看到那个标签.对不起,我的回答其余没有太大的意义和WPF,因为我没有WPF的大师,我真的不能说.但是,有一种方法可以解决这个问题.如果你可以改进它,那么在这里完全合法地挖掘另一个答案的内容.因此,如果有人知道如何使用WPF用户控件正确执行此操作,您可以自由解除我的答案的第一部分并添加WPF的相关位.

编辑:让我回答这里的评论中的问题.

由于所讨论的类是用户控件,因此其生命周期将与表单相关联.当表单关闭时,它将处理它拥有的所有子控件,换句话说,此处已存在Dispose方法.

用户控件来处理这个正确的方法,如果它管理自己的活动,是为了解开事件处理程序的Dispose方法.

(其余的删除)

  • 在.xaml.cs文件中,只需从IDisposable继承.像这样:`partial class MyUserControl:UserControl,IDisposable`.然后,您将能够实现dispose方法. (2认同)

Pau*_*oke 8

WPF不支持IDisposable.如果您正在实现需要清理的WPF控件,那么您应该考虑挂钩LoadedUnloaded事件(或者另外).

即您在Loaded处理程序中连接到事件并在处理程序中断开连接Unloaded.当然,这只是一个选项,如果您的控件不需要在没有"加载"的情况下接收事件,并且您可以正确支持许多加载/卸载周期.

使用Loaded/ Unloadedevents 的优点是您不必在任何使用它的地方手动配置用户控件.但是,您应该知道Unloaded在应用程序关闭开始后不会触发该事件.例如,如果您的关机模式是OnMainWindowClose,Unloaded则不会触发其他窗口的事件.这通常不是问题.它只是意味着你不能Unloaded在应用程序终止之前/期间必须发生的事情中做可靠的事情.


Tig*_*ran 7

首先我要说的是不要使用析构函数,而是使用Dispose()来清除资源.

其次,在我看来,如果这个代码是建立经常的对象内,寿命短,这是更好地照顾自己,移除事件处理程序,因为这是一个链接到支架的对象,这将防止GC收集它.

问候.