C# WPF 用户控件在父窗口关闭时不释放



我有一个主窗口,我们将调用main和一个子窗口,我们将调用child,我们将在child中调用用户控件control

程序从main开始,用户执行一些操作来启动具有controlchild具有FileSystemWatcher等功能。但是,我开始注意到FileSystemWatcher事件在关闭后仍在child触发。呃哦。所以我开始挖掘...

当我订阅Window_Closing事件时child它会按预期触发。 当我订阅UserControl_Unloaded事件control时,它会按预期触发(child关闭后立即触发)。 所以我在control上放了一个析构函数,这显然在关闭之前不会发生main

那么,为什么我的用户控件的析构函数在卸载用户控件时不释放属性呢?如果我知道哪些是相关的,我会包含代码片段......

好吧,在输入问题之后,StackOverflow的出色功能向我展示了这个问题,它有一个不错的通用答案。

我的解决方案是取消订阅UserControl_Unloaded事件中的所有FileSystemWatcher事件。 仅将观察程序对象设置为 null 是不够的。 对于像 .NET 这样的托管语言来说,这似乎工作量太大了,但我想不是。

FileSystemWatcher实现IDisposable。这通常表示类使用非托管资源(如文件句柄或非托管内存),垃圾回收器无法自动(或及时)回收这些资源。IDisposable提供了一种Dispose方法,此类类可以使用该方法正确释放其非托管资源。当然,清理也可以通过其他方法完成,但是IDisposable"约定"使程序员更容易看到哪些类需要清理。这也意味着"dispose"一词在 C# 中具有非常具体的含义。

看起来,如果不处理掉FileSystemWatcher,它仍然活着。由于您没有删除这些事件处理程序,因此它仍然包含对用户控件的引用,因此该控件也保持活动状态,并且您继续看到引发的事件。删除事件处理程序是一个好主意(尤其是当引发事件的对象具有较长的生命周期时),但在这种情况下,它只能解决症状,而不是根本问题:它允许用户控制被垃圾回收器回收,但FileSystemWatcher仍然有效。

至于析构函数(它们在 C# 中通常称为终结器),它们很少需要。它们可以被实现IDisposable的类用作最后的手段 - 以防万一程序员忘记调用Dispose- 但它们有一点成本(终结器需要在队列中注册,它们由特殊的终结器线程调用),并且您无法控制它们的确切执行时间。

最新更新