为SQLConnection.StateChange
事件添加事件处理程序的这两种不同方式有何不同,副作用和/或偏好?由于AddressOf
创建了委托(http://msdn.microsoft.com/en-us/library/y72ewk2b.aspx),而StateChangeEventHandler
也是委托,因此示例2似乎只是创建嵌套委托,但我猜测有一些委托我失踪的细微差别。
从我的测试中,它们似乎使用示例1或2工作相同。在尝试多次调用AddHandler时都没有抛出异常(我的第一个假设是,如果尝试调用AddHandler,调用示例#1会引发错误第二次,因为它将添加相同的引用,因为示例2不会,因为它将是一个新的委托实例;但是,它们都成功,没有例外)。
示例1:仅使用AddressOf
:http://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)
此外,是否需要在using
阻止RemoveHandler
阻止通过SQLConnection.Dispose
之前删除此处理程序,或者StateChangeEventHandler
会为您处理这个问题?我不确定如果在MSDN网站中使用下面示例#2中的StateChangeEventHandler
,将如何删除事件处理程序,因为RemoveHandler
委托的实例未存储在本地变量中,因此,您没有要删除的处理程序的引用(您必须执行与示例#4类似的操作)。
示例#3: 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
RemoveHandler
示例#4: 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
connection.StateChange += new StateChangeEventHandler(OnStateChange);
注意:我也标记为C#,因为MSDN文档也列出了C#示例的相同场景:
connection.StateChange += OnStateChange;
VS。
{{1}}
答案 0 :(得分:0)
我偶然发现了这篇文章(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将在最终确定时删除发布者上的事件引用。但是,如果您的发布商的使用寿命比订阅者长得多,则需要确保手动删除事件引用。在SQLConnection示例中,连接对象(即StateChange事件的发布者)的生命周期很短,因此可以说RemoveHandler
不需要。有关详情,请参阅此帖子:.NET object events and dispose / GC