我正在阅读这本书Under the hood of .NET memory management
(由Red-Gate出版)。您可以找到pdf version on their website。
我认为我理解了在发布者和订阅者之间创建的引用的事件处理程序,但作者'第5章和第34章中对事件处理程序的解释;特定于应用程序的问题" (标题为#34; Windows Presentation Foundation")让我困惑。
在第160-161页,他们描述了使用主/明细关系的UI设计。我引用(方括号之间的数字是我的,以便为我的问题创建引用,而不是那么多的意思):
您可能有一个包含列表的网格 主记录,当您从主网格中单击记录时,会出现一个新窗口 打开,显示与该主记录关联的详细信息。如果主窗口接通电源 在详细信息窗口[1]中的事件,然后细节窗口不能被垃圾收集,直到 主窗口中的事件处理程序释放它们对详细信息窗口的引用[2]。在这 例如,详细信息窗口将是监听器,主窗口是源[3]。多数情况 例如,主窗口将比详细信息窗口更长,但是如果事件处理程序是 处理不当,那么细节窗口就不能被垃圾收集了 主窗口还活着。
Detail.SomeEvent += new EventHandler(Master.SomeEvent_Handler); [4]
[1]这是非常不明确的术语。谁"连线"谁?仅凭这一点,我无法确定谁是听众以及谁是订阅者(我只能假设......)。下一句[3]似乎通过说主人是源而细节是听众来解答这个问题,但只是在通过在[2]中说明完全相反的情况引入混淆之后(因为imo事件处理程序在主窗口中不。
代码示例[4]也与[3]中所述内容相对应(但与[2]相对应)。如果主窗口是源,那么它应该是:
Master.SomeEvent += new EventHandler(Detail.SomeEvent_Handler); [5]
右?
除了所有这些混乱之外,我理解事件处理程序如下。如果Master
包含Detail
订阅的事件(如[5]所示),那么Master
会对Detail
产生一种拒绝(因为对实例删除的引用会创建一个引用实例,在这种情况下为Detail
。因此,只要Master
存在,Detail
也将保留在内存中,除非事件处理程序与事件分离。
我对这本书的批评和我自己的理解是否正确?
答案 0 :(得分:1)
C#语法糖从来都不是很明显。委托构造函数引用了两个参数。显而易见的是事件处理程序方法。非显而易见的是将要调用其处理程序方法的对象。不明显因为你从不在代码中输入它。它是this
。 C#甚至不允许您指定它,其他语言也可以。
所以Master对象现在如何引用Detail对象,正确调用事件处理程序方法。
因此只要Master对象处于活动状态,就不会收集Detail对象。除非您再次明确取消订阅该事件或使用WPF弱事件模式。或者,理想情况下,设计代码以使Master和Detail对象同时死亡。他们给了你一个不容易做的例子。
还有其他方法可以不使用事件。您可以使用表示您要引发的事件的方法声明IDetail接口。并为Master类提供AddDetail(IDetail)和RemoveDetail(IDetail)方法。现在,内存管理非常清晰,当您忘记调用RemoveDetail()时,内存管理变得更加明显。然而,WPF设计者非常喜欢使用事件,他们必须提出弱事件模式以避免他们自己的对象模型中的泄漏。