【发布时间】:2010-09-08 15:00:00
【问题描述】:
动态附加/分离事件处理程序有什么好处吗?
手动分离处理程序是否有助于确保不再有对已处置对象的引用?
【问题讨论】:
标签: vb.net .net-3.5 garbage-collection
动态附加/分离事件处理程序有什么好处吗?
手动分离处理程序是否有助于确保不再有对已处置对象的引用?
【问题讨论】:
标签: vb.net .net-3.5 garbage-collection
我很确定Handles 子句只是语法糖,它会将AddHandler 语句插入到您的构造函数中。我使用此代码进行了测试并禁用了应用程序框架,因此构造函数不会有额外的东西:
Public Class Form1
Public Sub New()
' This call is required by the Windows Form Designer. '
InitializeComponent()
' Add any initialization after the InitializeComponent() call. '
AddHandler Me.Load, AddressOf Form1_Load
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim breakpoint As Integer = 4
End Sub
End Class
IL 最终是这样的:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldarg.0
IL_000a: dup
IL_000b: ldvirtftn instance void WindowsApplication1.Form1::Form1_Load(object,
class [mscorlib]System.EventArgs)
IL_0011: newobj instance void [mscorlib]System.EventHandler::.ctor(object,
native int)
IL_0016: call instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler)
'... lots of lines here '
IL_0047: ldarg.0
IL_0048: callvirt instance void WindowsApplication1.Form1::InitializeComponent()
IL_004d: nop
IL_004e: ldarg.0
IL_004f: ldarg.0
IL_0050: dup
IL_0051: ldvirtftn instance void WindowsApplication1.Form1::Form1_Load(object,
class [mscorlib]System.EventArgs)
IL_0057: newobj instance void [mscorlib]System.EventHandler::.ctor(object,
native int)
IL_005c: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler)
IL_0061: nop
IL_0062: nop
IL_0063: ret
} // end of method Form1::.ctor
注意 IL_000b 和 IL_0051 周围有两个相同的代码块。我认为这只是语法糖。
【讨论】:
这不是使用 AddHandler 还是使用 Handles 的问题。
如果您担心对事件处理程序的引用会干扰垃圾收集,则无论处理程序是如何附加的,您都应该使用 RemoveHandler。在窗体或控件的 Dispose 方法中,删除所有处理程序。
我在 Windows 窗体应用程序(.NET 1.1 天)中遇到过这样的情况,即在没有其他引用的控件上调用事件处理程序(并且出于所有意图和目的,这些控件已死,我原以为是 GC 'ed) -- 极难调试。
我会使用 RemoveHandler 来删除您不会重用的控件上的处理程序。
【讨论】:
将字段声明为WithEvents 将导致编译器自动生成具有该名称的属性。 getter 返回支持字段的值。设置器稍微复杂一些。它首先检查支持字段是否已经具有正确的值。如果是,则退出。否则,如果支持字段不为空,它会向支持字段标识的对象发出针对其所有事件的“RemoveHandler”请求。接下来,无论支持字段是否为非空,它都将其设置为等于请求的值。最后,如果新值不为空,无论旧值是否为空,该属性都会向新值标识的对象发出“AddHandler”请求,以获取其所有事件。
如果放弃前将对象的所有WithEvents成员设置为Nothing,并避免在多个线程中操作WithEvents成员,则自动生成的事件代码不会泄漏。
【讨论】:
我发现动态附加/分离事件处理程序仅在您有一个长期存在的对象公开被许多短期对象使用的事件时使用。对于大多数其他情况,这两个对象大约在同一时间被放置,CLR 自己完成了足够的清理工作
【讨论】:
我在手动创建控件时手动附加处理程序(例如,为每个数据库记录动态创建一个 TextBox)。我在处理我还没有准备好处理的事情时手动分离处理程序(可能是因为我使用了错误的事件?:))
【讨论】:
手动分离事件对于防止内存泄漏非常重要:连接到由另一个对象触发的事件的对象,在触发事件的对象被垃圾回收之前不会被垃圾回收。换句话说,“事件引发者”对与其相关的所有“事件监听者”有很强的引用。
【讨论】:
大多数时候框架会为您处理这些问题。
【讨论】: