【问题标题】:SQLConnection.StateChange Event AddHandler using StateChangeEventHandler vs AddressOfSQLConnection.StateChange 事件 AddHandler 使用 StateChangeEventHandler 与 AddressOf
【发布时间】:2014-05-09 16:33:07
【问题描述】:

这两种为SQLConnection.StateChange 事件添加事件处理程序的不同方式有什么区别、副作用和/或偏好?由于 AddressOf 创建了一个委托 (http://msdn.microsoft.com/en-us/library/y72ewk2b.aspx),而 StateChangeEventHandler 也是一个委托,因此示例 2 似乎只是在创建嵌套委托,但我猜我缺少一些细微差别。

从我的测试来看,无论是使用示例 1 还是示例 2,它们似乎都可以正常工作。尝试多次调用 AddHandler 时都不会引发异常(我的第一个假设是,如果尝试调用 AddHandler,调用示例 #1 会引发错误第二次,因为它将添加相同的引用,而示例 2 不会添加相同的引用,因为它将是一个新的委托实例;但是,它们都成功而没有例外)。

示例1:仅使用AddressOfhttp://msdn.microsoft.com/en-us/library/7taxzxka.aspx

AddHandler conn.StateChange, AddressOf OnConnectionStateChange

示例 2: 使用此处列出的 StateChangeEventHandler 委托的实例:http://msdn.microsoft.com/en-us/library/a0hee08w(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-2

AddHandler conn.StateChange, New StateChangeEventHandler(AddressOf OnConnectionStateChange)

另外,在通过RemoveHandler 处理/结束using 块之前是否需要删除此处理程序,或者SQLConnection.Dispose 会为您处理这些?我不确定如果从 MSDN 站点使用下面示例#2 中的StateChangeEventHandler,您将如何删除事件处理程序,因为StateChangeEventHandler 委托的实例未存储在局部变量中,因此您没有参考要删除的处理程序(您必须执行类似于示例 #4 的操作)。

示例 #3: RemoveHandler 仅使用 AddressOf

    Using conn As SqlConnection = New SqlConnection("...")
        AddHandler conn.StateChange, AddressOf OnConnectionStateChange
        conn.Open()
        '...do work here...
        conn.Close()
        'Then do i need this?
        RemoveHandler conn.StateChange, AddressOf OnConnectionStateChange
    End Using

示例 #4: RemoveHandler 使用 StateChangeEventHandler

    Using conn As SqlConnection = New SqlConnection("...")
        Dim myHandler As StateChangeEventHandler = New StateChangeEventHandler(AddressOf OnConnectionStateChange)
        AddHandler conn.StateChange, myHandler
        conn.Open()
        '...do work here...
        conn.Close()
        'Then do i need this?
        RemoveHandler conn.StateChange, myHandler
    End Using

注意:我也标记为 C#,因为 MSDN 文档还列出了 C# 示例的相同场景:

connection.StateChange  += new StateChangeEventHandler(OnStateChange);

对比

connection.StateChange  += OnStateChange;

【问题讨论】:

    标签: c# .net vb.net events event-handling


    【解决方案1】:

    我偶然发现了这篇文章 (http://msdn.microsoft.com/en-us/library/74wy9422(v=vs.90).aspx),其中提到 AddressOf 只是 New EventHandler(AddressOf fn) 的简写。

    AddHandler Button1.Click, New EventHandler(AddressOf Button1_Click)
    ' The following line of code is shorthand for the previous line. 
    AddHandler Button1.Click, AddressOf Me.Button1_Click
    

    它还指出:

    您可以在任何地方使用简写方式创建委托 编译器可以通过上下文确定委托的类型

    所以在大多数情况下,使用New SomeEventHandlerType(AddessOf x) 或仅使用AddressOf x 可以完成同样的事情。在SQLConnection.StateChange 的情况下,事件被声明为Public Event StateChange As StateChangeEventHandler,因此编译器知道要使用的正确委托类型,并且AddressOf 足够聪明,可以自动为您使用正确的委托类型。没有必要使用New StateChangeEventHandler(AddressOf OnConnectionStateChange),但它可以用于代码清晰,以表明这不是通用的 EventHandler 委托类型,并且它使用自定义的 EventArgs 类型。

    就取消订阅而言,为了绝对避免资源泄漏,您应该在处理订阅者对象之前删除事件处理程序引用。请参阅http://msdn.microsoft.com/en-us/library/ms366768(v=vs.120).aspx,其中指出:

    为了防止资源泄漏,您应该取消订阅事件 在处理订阅者对象之前。直到您取消订阅 一个事件,作为事件基础的多播委托 发布对象具有对封装的委托的引用 订阅者的事件处理程序。只要发布对象持有 该引用,垃圾收集不会删除您的订阅者 对象。

    在实际实践中,我很少看到这样做的示例(即使在 MSDN“如何:发布符合 .NET Framework 指南的事件”http://msdn.microsoft.com/en-us/library/w369ty8x.aspx 中也是如此)。 GC 将在最终确定时负责删除发布者上的事件引用。但是,如果您遇到 publisher 的寿命比 subscriber 长得多的情况,则需要确保手动删除事件引用。在 SQLConnection 示例中,连接对象(即 StateChange 事件的 publisher)的生命周期很短,因此可以说不需要 RemoveHandler。更多详情见此帖:.NET object events and dispose / GC

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-20
      • 1970-01-01
      • 1970-01-01
      • 2010-09-08
      • 2014-12-21
      • 1970-01-01
      相关资源
      最近更新 更多