6

为什么这不一样?!

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
4

2 回答 2

4

使用Option Strict On是避免此类意外的好方法。你会得到一个“你到底想做什么?” 来自编译器的错误消息。

但是在它关闭的情况下,这些是有效的语句,由 DLR(动态语言运行时)执行。它能够评估像这样的后期绑定表达式。然而,它有一个可以为空的类型的问题,例如Integer?. 它需要处理值的盒装版本。这很简单。而且 Nothing 没有任何与之关联的类型信息。DLR 无法看到它以可空整数的形式开始,因为它只知道它可能是一个空字符串

编译器也无能为力,它无法发出任何代码来使表达式遵循正常的评估规则。它只知道有一个函数,它不知道是哪个函数,它的名字是“MyFunction”,不知道它返回什么样的值。它把责任转嫁给 DLR 来解决。

因此,DLR 只是对它进行了抨击。它提出了“不知道”+ 0 = 0。鉴于它确实具有 0 的类型信息。它是一个整数,因此它也尝试将左运算符解释为整数。这是有效的,Nothing 是 Integer 的正确默认值。

功能,而不是错误。

于 2014-12-18T12:03:47.470 回答
2

Visual Basic .NET 早Nothing在拥有可空值类型之前就已经存在 - 它是从 .NET 之前的 Visual Basic 继承而来的。在某些情况下,它的行为更像 C#default(T)然后 t null

您的最终调用是调用AddObjectVisual Basic 编译器服务中的方法。这种方法已经存在了很长时间,并且再次早于可空值类型,不幸的是没有很好的文档记录。

不幸的是,它们不能使可空类型的行为绝对一致,尤其是在面对后期绑定调用时,同时仍保持向后兼容性。例如,这也打印0

Console.WriteLine(CType(CType(Nothing, Object), Int32))
于 2014-12-18T11:57:24.110 回答