动态附加/分离事件处理程序是否有优势?
手动分离处理程序是否有助于确保没有对已处置对象的引用?
答案 0 :(得分:3)
我很确定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周围的两个相同的代码块。我认为这只是语法糖。
答案 1 :(得分:2)
这不是使用AddHandler与Handles的问题。
如果您担心对事件处理程序的引用会干扰垃圾回收,那么无论处理程序是如何附加的,都应该使用RemoveHandler。在窗体或控件的Dispose方法中,删除所有处理程序。
我遇到过Windows窗体应用程序(.NET 1.1天)中的情况,其中将在没有其他引用的控件上调用事件处理程序(并且对于所有意图和目的都已经死了,我认为是GC 'ed) - 非常难以调试。
我会使用RemoveHandler去除你不会重用的控件上的处理程序。
答案 2 :(得分:2)
将字段声明为WithEvents
将导致编译器自动生成具有该名称的属性。 getter返回支持字段的值。制定者有点复杂。它首先检查支持字段是否已具有正确的值。如果是这样,它会退出。否则,如果支持字段为非null,则会将其所有事件的“RemoveHandler”请求发送到由支持字段标识的对象。接下来,无论后备字段是否为非null,它都将其设置为等于请求的值。最后,如果新值为非null,无论旧值是否为空,该属性都会向新值标识的对象发出“AddHandler”请求。
如果在放弃对象之前将对象的所有WithEvents成员设置为Nothing
,并且避免在多个线程中操纵WithEvents成员,则自动生成的事件代码不会泄漏。
答案 3 :(得分:1)
我发现动态附加/分离事件处理程序只适用于长期存在的对象公开许多短期对象所消耗的事件的情况。对于大多数其他情况,这两个对象大约在同一时间处理,CLR可以自行清理
答案 4 :(得分:1)
手动创建控件时手动附加处理程序(例如,为每个数据库记录动态创建TextBox)。当他们处理我还没准备好处理的事情时,我手动分离处理程序(可能是因为我使用了错误的事件?:)
答案 5 :(得分:0)
大多数情况下,框架会为您解决这个问题。
答案 6 :(得分:0)
手动分离事件对于防止内存泄漏非常重要:连接到另一个对象触发的事件的对象不会被垃圾收集,直到触发事件的对象被垃圾回收。换句话说,“事件提升者”强烈提及与之相关的所有“事件听众”。