VB.net是怎样做到的(四、五)

VB.net 是怎样做到的(三)—— Handles 和 WithEvents

VB 除了可以用 C# 那样的方法来处理事件响应以外,还有从 VB5 继承下来的独特的事件处理方式—— WithEvents 。

我喜欢称这种事件处理方式为静态的事件处理,书写响应事件的方法时就已经决定该方法响应的是哪一个事件,而 C# 则是在代码中绑定事件的。比如下面这个最简单的例子:

Public Class HandlerClass
Public WithEvents MyObj As EventClass

Private Sub MyObj_MyEvent( ByVal sender As Object , ByVal e As System.EventArgs ) Handles MyObj.MyEvent
MsgBox("hello")
End Sub

Public Sub New ()
MyObj = New EventClass
End Sub
End Class

代码中用到的 EventClass 是这样的:

Public Class EventClass
Public Event MyEvent As EventHandler

Protected Overridable Sub OnMyEvent( ByVal e As EventArgs )
RaiseEvent MyEvent(Me, e)
End Sub

Public Sub Test()
OnMyEvent( New EventArgs )
End Sub
End Class

我们来复习一下,这段代码隐式地给 EventClass 编写了两个方法—— Add_MyEvent(EventHandler) 和 Remove_MyEvent(EventHandler) ,实际上任何使用事件的上下文都是通过调用这两个方法来绑定事件和解除绑定的。 C# 还允许你书写自己的事件绑定 / 解除绑定的代码。

那么 WithEvents 是怎么工作的呢? VB.net 的编译器在编译时自动将

Public WithEvents MyObj As EventClass

翻译成下面这个过程:

Private _MyObj As EventClass

Public Property MyObj() As EventClass
Get
Return _MyObj
End Get
Set ( ByVal Value As EventClass )

If Not ( Me ._MyObj Is Nothing ) Then
RemoveHandler _MyObj.MyEvent, New EventHandler ( AddressOf MyObj_MyEvent)
End If

Me ._MyObj = Value

If Me ._MyObj Is Nothing Then Exit Property

AddHandler _MyObj.MyEvent, New EventHandler ( AddressOf MyObj_MyEvent)

End Set
End Property

由此可见,当对 WithEvents 变量赋值的时候,会自动触发这个属性以绑定事件。我们所用的大部分事件响应都是 1 对 1 的,即一个过程响应一个事件,所以这种 WithEvents 静态方法是非常有用的,它可以显著增强代码可读性,同时也让 VB.net 中的事件处理非常方便,不像 C# 那样离开了窗体设计器就必须手工绑定事件。

不过在分析这段 IL 的时候,我也发现了 VB.net 在翻译时小小的问题,就是 ldarg.0 出现得过多,这是频繁使用 Me 或 this 的表现,所以我们在编码过程中一定要注意,除了使用到 Me/this 本身引用以外,使用它的成员时不要带上 Me/this ,比如 Me.MyInt = 1 就改成 MyInt = 1 ,这样的小习惯会为你带来很大的性能收益。

VB.net 是怎样做到的(四)——类型转换

今天在 www.aspx.cn 看到了 一篇帖子 ,看到 wyhw 大侠真的希望 dotnet blog 成为 .NET 的精品技术 Blog 。所以我也不能偷懒了,赶快学习,并且多发技术帖子。
回到正题来,我今天在 Visual Basic 社区上看到在 Visual Basic 2005 中将加入一个新的运算符—— TryCast ,相当于 C# 的 as 运算符。我一直希望 VB 有这样一个运算符,既然今天看到了,就顺便研究一下 VB 和 C# 的类型转换。先说 VB ,类型转换运算符主要有 CType 和 DirectCast 。他们的用法几乎一样。我详细比较了一下这两个运算符,得出以下结论:

1 、在转换成引用类型时,两者没有什么区别,都是直接调用 castclass 指令,除非重载了类型转换运算符(当然 VB.NET 还不行,但我没有 VB 2005 ,所以没法试验)。

2 、转换成值类型时, CType 会调用 VB 指定的类型转换函数(如果有的话),比如将 String 转换为 Int32 时,就会自动调用 VisualBasic.CompilerServices.IntegerType.FromString ,而将 Object 转换为 Int32 则会调用 FromObject 。其他数值类型转换为 Int32 时, CType 也会调用类型本身的转换方法实施转换。 DirectCast 运算符则很简单,直接将对象拆箱成所需类型。

所以在用于值类型时, CType 没有 DirectCast 快速但可以支持更多的转换。在 C# 中,类型转换则为( type) 运算符和 as 运算符。 (type) 运算符的工作方式与 VB 的 DirectCast 很相似,也是直接拆箱或 castclass 的,但是如果遇到支持的类型转换(如 long 到 int ), (type) 运算符也会调用相应的转换方法,但不支持从 String 到 int 的转换。 C# 另一个运算符 as 则更加智能,它只要判断对象的运行实例能否转成目标类型,然后就可以省略 castclass 指令,直接按已知类型进行操作,而且编译器还可以自动对 as 进行优化,比如节省一个对象引用等。所以在将 Object 转换成所需的类型时, as 是最佳选择。

由于 as 有很多优点, Visual Basic 2005 将这一特性吸收了过来,用 TryCast 运算符就可以获得和 as 一样的效果,而且语法与 DirectCast 或 CType 一样。

Published At
Categories with Web编程
Tagged with
comments powered by Disqus