有趣的事件:“Dispose”行为

3
我注意到我们的.NET WinForms应用程序中有趣的行为。我们有一个包含许多mdi子窗体的mdi窗体。这些子窗体侦听“广播”事件,本质上是调用刷新自身。该事件在基类中声明,并在子窗体中添加了侦听事件。
我注意到,即使关闭这些子窗体,如果不在Dispose()方法中明确删除事件,则仍会触发事件。
这背后的原因是什么?如果窗体已关闭,事件不应该被拆除/处理吗?这是否因为实际事件本身在外部类中声明?这就是我的推测。
非常感谢提供帮助。(使用C#,.NET 3.5)
4个回答

4
该事件仍在范围内,因为它在主表单上,仍然引用子窗口中的委托。因此,关闭窗口不会处理该对象,因为通过此引用,该对象也仍在作用域内。这是.NET中出现“内存泄漏”的常见方式。还要考虑到,由于子窗口仍在作用域内,窗口内的所有内容也仍在作用域内,因此也不会被收集。
至于为什么窗口在关闭时不会分离所有事件处理程序。如果它这样做,那将是非常奇怪的行为。仅仅因为你关闭了一个窗口并不意味着你已经完成了它,你可以重新打开它,保存其中的数据以保持状态。调用窗口的关闭方法与调用任何其他方法没有特殊属性,它不会处理窗口,标记它进行收集或执行任何其他操作。

1

你说得对。当你注册一个事件时,你的表单的引用会被添加到事件委托中(在拥有该事件的对象中)。除非你取消注册,否则你的表单永远不会被垃圾回收,因为它仍然至少有一个引用(委托),并且在事件被触发时调用仍将被发出。

你应该始终确保取消订阅事件,以避免这种泄漏。


1

是的,这是按设计的行为,也是WeakEvent模式被构思的原因。


0

你的事件订阅“计数”作为对你的子表单的引用。(因此,你的子表单也不会被垃圾回收。)

要查看发生了什么,请查找委托的帮助。它有一个称为Target的成员(类型为object),指向订阅者。所以,你仍然有一个引用链处于活动状态:

MDI 父窗体(事件发布者)--> 委托 --> 你的子窗体。

你必须在Dispose()中清理你的事件订阅,否则你的子表单将永远无法进行垃圾回收。

现在,如果你在网上寻找“弱引用事件”,你会发现许多人发布了定义弱事件的解决方法。这里只是一个例子:http://www.codeproject.com/KB/cs/weakeventhandlerfactory.aspx

我也不得不原型化其中之一,如果你需要,我很乐意分享。但是,我的建议是坚持使用常规事件并在Dispose()中进行清理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接