为什么会不一样?!
Public Class Form1
Public Function MyFunction() As Integer?
Return Nothing
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim o As Object = Me
MsgBox(TypeName(Me)) ' Form1
MsgBox(TypeName(o)) ' Form1
MsgBox(TypeName(Me.MyFunction())) ' Nothing
MsgBox(TypeName(o.MyFunction())) ' Nothing
' but
MsgBox(TypeName(Me.MyFunction() + 0)) ' Nothing
MsgBox(TypeName(o.MyFunction() + 0)) ' Integer
End Sub
End Class
使用
Option Strict On
是避免此类意外的好方法。你会得到一个“你到底想做什么?”来自编译器的错误消息。
但关闭后,这些都是有效的语句,由 DLR(动态语言运行时)执行。它能够评估像这样的后期绑定表达式。然而,它对于像
Integer?
这样的可空类型有一个问题。它需要处理值的boxed版本。这根本就是什么都没有。 Nothing 没有任何与之关联的类型信息。 DLR 无法采取任何措施来查看这个以可为空整数开始的生命周期,因为它知道它可能是一个“Nothing”的string。
编译器也无能为力,它无法发出任何代码来使表达式遵循正常的求值规则。它只知道有一个 some 函数,但它不知道是哪个函数,其名称是“MyFunction”,也不知道它返回什么样的值。它把责任推给 DLR 来解决。
所以德国航天中心只是押注它。它得出“不知道”+ 0 = 0。鉴于它确实具有0的类型信息。它是一个整数,因此它也尝试将左运算符解释为整数。这是有效的,Nothing 是 Integer 的正确默认值。
功能,而不是错误。
Visual Basic .NET 早在拥有可空值类型之前就已经拥有
Nothing
- 它从 .NET 之前的 Visual Basic 继承了它。在某些情况下,它的行为更像 C# 的 default(T)
,然后 t 则 null
。
您的最后一个调用是调用 Visual Basic 编译器服务中的
AddObject
方法。这种方法已经存在很长时间了,并且再次早于可为空值类型,不幸的是没有很好的记录。
不幸的是,他们无法使可空类型的行为绝对一致,特别是在面对后期绑定调用时,同时仍然保持向后兼容性。例如,这也会打印
0
:
Console.WriteLine(CType(CType(Nothing, Object), Int32))