【IT168 技术文档】
空类型
关系数据库引入了空值的语义,空值和当前的普通程序设计语言经常不一致,程序员也不熟悉它。在以数据为中心的程序中,正确清晰地理解这些语义是很重要的。考虑到这一点,在"Whidbey"里CLR使用泛型Nullable(Of T As Struct)加入了对空特性的运行时支持。使用这个类型我们可以声明各种值类型的空版本,如Integer,Boolean和Data等等。为了明显起见,VB中空类型的语法为T?。
举例来说,并不是所有国家都是独立的,我们可以给类Country加上一个新的成员代表他们的独立时间:
Partial Class
Country Public Property Independence As Date?
End Class
和数组类型一样,我们也可以给属性名加上可为空的修饰语,如下声明:
Partial Class
Country Public Property Independence? As Date
End Class
帕劳群岛的独立时间是#10/1/1994#,不过Virgin岛是英联邦的属地,因而它的独立日是Nothing:
Dim Palau = _
New Country { _
.Name = "Palau", _
.Area = 458, _
.Population = 16952, _
.Independence = #10/1/1994# }
Dim VirginIslands = _
New Country { _
.Name = "Virgin Islands", _
.Area = 150, _
.Population= 13195, _
.Independence = Nothing }
Visual Basic 9.0支持在空值上的三值逻辑和空传播算术,这意味着如果其中一个算术,比较,逻辑或者位,转换,或者类型操作的操作数是Nothing,结果就是Nothing。如果两个操作数都是适当的值,操作将根据操作数的值来决定,结果被转化为空。
因为Palau.Independence和VirginIslands.Independence都是Date?类型,编译器将使用空传播算术来进行下面的提取,因此对于本地声明PLength和VILength的推断类型就都是TimeSpan?。
Dim PLength = #8/24/2005# - Palau.Independence REM 3980.00:00:00
PLength的值是3980.00:00:00因为没有操作数是Nothing。另外,由于VirginIslands.Independence的值是Nothing,结果类型也是TimeSpan?,但是因为空传播的原因VILength的值是Nothing。
Dim VILength = #8/24/2005# - VirginIslands.Independence REM Nothing
在SQL里,比较操作符将会做空传播,逻辑员算府将会使用三值逻辑。在If和While语句中,Nothing将会理解为False;因此在如下代码里,使用了Else分支:
If VILength < TimeSpan.FromDays(10000)
...
Else
...
End If
注意在三值逻辑里,等式检查X = Nothing,但是Nothing = X总是等同于Nothing;为了检查X是否是Nothing,我们应该用双值逻辑比较X Is Nothing或者Nothing Is X。
在打包和解包时,运行时将会把控制看作是Object来处理。当打包一个代表Nothing的空值时(HasValue属性为False),值将会被打包进一个空引用。当打包一个合适的值时(HasValue属性为True),当前值将会首先被解开,然后再打包。因为这样,没有堆里的对象是动态类型Nullable(Of T);所有这样明显的类型都是T。同时,我们也可以从Object中解包值然后放入到T或者Nullable(Of T)。然而,这样做的结果是后期绑定不能动态的决定是否使用三值逻辑或者双值逻辑。举例来说,当我们做一个两个数的早期绑定的相加时,一个数是Nothing,将使用空操作,结果就是Nothing:
Dim A As Integer? = Nothing
Dim B As Integer? = 4711
Dim C As Integer? = A+B
REM C = Nothing
然而,当使用两个值的后期绑定相加时,结果是4711,因为A和B的动态类型都是Integer而不是Integer?,后期绑定将会使用双值逻辑。这里Nothing被解释为0:
Dim X As Object = A
Dim Y As Object = B
Dim Z As Object = X+Y
REM Z = 4711
为了保证正确地语义,我们需要引导编译器使用空传播重载:
Operator +(x As Object?, y As Object?) As Object?
通过使用?操作符转化任意一个操作数为空类型:
Dim X As Object = A
Dim Y As Object = B
Dim Z As Object? = X?+Y
REM Z = Nothing
注意这里我们必须能够从任何类型T来创建T?。当前的CLR Nullable(Of T As Struct)类型限制只能使用非空结构的参数类型。T如果不是一个非空值的类型,Visual Basic编译器将会把T?转化为T,否则转化为Nullable(Of T)。编译器将会在VB程序里保留足够的内部元数据以记住载此两种情况下静态类型都是T?。
非严格委托
当使用AddressOf或者Handles在Visual Basic 8.0创建一个委托时,要和委托标识符绑定的方法之一必须要和委托类型的署名相一致。在如下例子中,OnClick子程序的署名必须和事件句柄委托Delegate Sub EventHandler(sender As Object, e As EventArgs)一致,该委托是在Button类型后声明的:
Dim WithEvents B As New Button()
Sub OnClick(sender As Object, e As EventArgs) Handles B.Click
MessageBox.Show("Hello World from" + B.Text)
End Sub