【问题标题】:Handles vs. AddHandler句柄与 AddHandler
【发布时间】:2010-09-08 15:00:00
【问题描述】:

动态附加/分离事件处理程序有什么好处吗?

手动分离处理程序是否有助于确保不再有对已处置对象的引用?

【问题讨论】:

    标签: vb.net .net-3.5 garbage-collection


    【解决方案1】:

    我很确定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 周围有两个相同的代码块。我认为这只是语法糖。

    【讨论】:

      【解决方案2】:

      这不是使用 AddHandler 还是使用 Handles 的问题。

      如果您担心对事件处理程序的引用会干扰垃圾收集,则无论处理程序是如何附加的,您都应该使用 RemoveHandler。在窗体或控件的 Dispose 方法中,删除所有处理程序。

      我在 Windows 窗体应用程序(.NET 1.1 天)中遇到过这样的情况,即在没有其他引用的控件上调用事件处理程序(并且出于所有意图和目的,这些控件已死,我原以为是 GC 'ed) -- 极难调试。

      我会使用 RemoveHandler 来删除您不会重用的控件上的处理程序。

      【讨论】:

        【解决方案3】:

        将字段声明为WithEvents 将导致编译器自动生成具有该名称的属性。 getter 返回支持字段的值。设置器稍微复杂一些。它首先检查支持字段是否已经具有正确的值。如果是,则退出。否则,如果支持字段不为空,它会向支持字段标识的对象发出针对其所有事件的“RemoveHandler”请求。接下来,无论支持字段是否为非空,它都将其设置为等于请求的值。最后,如果新值不为空,无论旧值是否为空,该属性都会向新值标识的对象发出“AddHandler”请求,以获取其所有事件。

        如果放弃前将对象的所有WithEvents成员设置为Nothing,并避免在多个线程中操作WithEvents成员,则自动生成的事件代码不会泄漏。

        【讨论】:

          【解决方案4】:

          我发现动态附加/分离事件处理程序仅在您有一个长期存在的对象公开被许多短期对象使用的事件时使用。对于大多数其他情况,这两个对象大约在同一时间被放置,CLR 自己完成了足够的清理工作

          【讨论】:

            【解决方案5】:

            我在手动创建控件时手动附加处理程序(例如,为每个数据库记录动态创建一个 TextBox)。我在处理我还没有准备好处理的事情时手动分离处理程序(可能是因为我使用了错误的事件?:))

            【讨论】:

              【解决方案6】:

              手动分离事件对于防止内存泄漏非常重要:连接到由另一个对象触发的事件的对象,在触发事件的对象被垃圾回收之前不会被垃圾回收。换句话说,“事件引发者”对与其相关的所有“事件监听者”有很强的引用。

              【讨论】:

                【解决方案7】:

                大多数时候框架会为您处理这些问题。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-05-26
                  • 2011-07-03
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多