动态附加/分离事件处理程序有优势吗?
手动分离处理程序是否有助于确保没有对已处置对象的引用?
我很确定该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 处理) -- 极难调试。
我会使用 RemoveHandler 摆脱您不会重用的控件上的处理程序。
将字段声明为WithEvents
将导致编译器自动生成具有该名称的属性。getter 返回支持字段的值。设置器稍微复杂一些。它首先检查支持字段是否已经具有正确的值。如果是,则退出。否则,如果支持字段不为空,它会向支持字段标识的对象发出针对其所有事件的“RemoveHandler”请求。接下来,无论支持字段是否为非空,它都将其设置为等于请求的值。最后,如果新值不为空,无论旧值是否为空,该属性都会向由新值标识的对象发出“AddHandler”请求,以获取其所有事件。
只要在放弃对象前将对象的所有 WithEvents 成员设置为Nothing
,并避免在多个线程中操作 WithEvents 成员,自动生成的事件代码就不会泄漏。
我发现动态附加/分离事件处理程序仅在您有一个长期存在的对象公开被许多短期对象使用的事件时使用。在大多数其他情况下,这两个对象大约在同一时间被放置,并且 CLR 自己完成了足够的清理工作
我在手动创建控件时手动附加处理程序(例如,为每个数据库记录动态创建一个 TextBox)。我在处理我还没有准备好处理的事情时手动分离处理程序(可能是因为我使用了错误的事件?:))
大多数时候,框架会为您处理这些问题。
手动分离事件对于防止内存泄漏非常重要:连接到另一个对象触发的事件的对象,在触发事件的对象被垃圾回收之前不会被垃圾回收。换句话说,“事件引发者”对与其相关的所有“事件监听者”有很强的引用。