VB.NET:来自`Nothing`的布尔值有时是`false`,有时是Nullreference-Exception

时间:2011-01-26 11:59:29

标签: .net vb.net .net-3.5 compiler-construction casting

来自 Basic boolean logic in C# ,我想知道原因:

Dim b As Boolean
Dim obj As Object = Nothing
'followig evaluates to False'
b = DirectCast(Nothing, Boolean)
'This throws an "Object reference not set to an instance of an object"-Exception'
b = DirectCast(obj, Boolean)

CType(obj, Boolean)会评估为False(就像CBool(obj))。我认为这是因为编译器使用辅助函数,但这不是我的主题。

为什么将Nothing转换为Boolean评估为False,而将Nothing的对象转换为Boolean会抛出Nullreference-Exception?这有意义吗?

[Option Strict ON]

5 个答案:

答案 0 :(得分:15)

据推测,这是因为VB.NET中的Nothing与C#中的null不完全相同。

对于值类型,Nothing表示该类型的默认值。对于Boolean,默认值为False,因此投射成功。

  

值类型(如Integer)或结构和引用类型(如Form或String)之间的主要区别之一是引用类型支持空值。也就是说,引用类型变量可以包含值Nothing,这意味着该变量实际上并不引用值。相反,值类型变量始终包含值。 Integer变量始终包含一个数字,即使该数字为零。如果将值Nothing赋值给值类型变量,则只为值类型变量赋值为默认值(在Integer的情况下,默认值为零)。当前CLR中无法查看Integer变量并确定它是否从未被赋值 - 它包含零的事实并不一定意味着它没有被赋值。   
- The Truth about Nullable Types and VB...

编辑:为了进一步说明,第二个示例在运行时抛出NullReferenceException的原因是因为CLR正在尝试取消装箱Object(引用类型) )到Boolean。当然,这会失败,因为对象是使用空引用初始化的(将其设置为Nothing):

Dim obj As Object = Nothing

请记住,正如我上面所解释的,当涉及到引用类型时,VB.NET关键字Nothing仍然与C#中null的工作方式相同。这就解释了为什么你得到一个NullReferenceException,因为你试图投射的对象实际上是一个空引用。它根本不包含任何值,因此无法取消装箱到Boolean类型。

当您尝试将关键字Nothing强制转换为布尔值时,您看不到相同的行为,即:

Dim b As Boolean = DirectCast(Nothing, Boolean)

因为关键字Nothing(这次,在值类型的情况下)只是意味着“此类型的默认值”。如果是Boolean,那就是False,因此演员阵容合乎逻辑且直截了当。

答案 1 :(得分:4)

你必须要在这里实现一些事情。

第一个是其他人已经指出的:Nothing 可以被VB编译器解释为Boolean值{{ 1}}给出适当的上下文,例如False

这意味着当编译器看到这个时:

Dim b As Boolean = Nothing

它会看到文字(b = DirectCast(Nothing, Boolean) )并且还会看到您要将此文字用作Nothing。这使得它成为一个明智的选择。

但是现在这是第二个你需要意识到的事情。 Boolean上的DirectCast本质上是一个拆箱操作(对于值类型)。那么从VB编译器的角度来看,需要发生的是:需要在该框中成为Object,否则操作将失败。因为实际上框中没有 nothing - 这次我们真的在讨论 nothing ,就像在Boolean中一样 - 它会引发异常。

如果我要将此代码翻译成C#,它将如下所示:

null

希望这会让事情更清楚一点?

答案 2 :(得分:2)

使用关键字(文字)Nothing和使用值为Nothing的参考变量之间存在差异。

  • 在VB.NET中,文字(关键字)Nothing得到特殊处理。 Nothing 关键字可以使用该类型的默认值自动转换为值类型。

  • 值为Nothing的参考变量不同。你没有得到特殊的行为。

  • 文档说DirectCast“需要两个参数的数据类型之间的继承或实现关系”。

  • 显然Object不会继承或实施Boolean,除非您已将盒装Boolean放入对象变量中。

因此下面的代码在运行时失败并出现异常。

 Dim obj As Object = Nothing  
 b = DirectCast(obj, Boolean) 

答案 3 :(得分:1)

要获得预期的行为,您需要以下代码:

Dim b As Boolean?
Dim obj As Object = Nothing  
b = DirectCast(obj, Boolean?) 

字符?表示Nullable(of )

答案 4 :(得分:1)

我发现将布尔变量与“True”,“False”字符串进行比较或似乎无法确保我得到正确的比较。我正在使用一个函数返回一个div的html字符串,其中包含一个已检查或未选中的单选按钮的图像,并且没有任何回复的问题。使用变量=“True”或“False”字符串并使用IS NOTHING进行最后一次检查有助于解决该问题。

Dim b as boolean = nothing

response.write CheckValue(b = "True")
response.write (b = "False")
response.write (b is nothing)

Function CheckValue(inVal as boolean) as string
  if inVal then 
    return ("<div><img src="checked.png" ></div>
  else
    return ("<div><img src="unchecked.png" ></div>    
  end if
end function

系统似乎在与字符串进行隐式比较时进行字符串转换,而使用 .tostring 方法只会创建错误,同时允许最后一次比较实际比较值

希望这有点帮助。它至少让我