VB.NET:布尔值来自'Nothing',有时为'false',有时为Nullreference异常

VB.NET:布尔值来自'Nothing',有时为'false',有时为Nullreference异常,.net,vb.net,.net-3.5,compiler-construction,casting,.net,Vb.net,.net 3.5,Compiler Construction,Casting,我来自美国,我想知道为什么: 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,Boole

我来自美国,我想知道为什么:

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))
。我认为这是因为编译器使用了一个helper函数,但这不是我的主题

为什么将
Nothing
强制转换为
Boolean
会计算为
False
,而将
Nothing
的对象强制转换为
Boolean
会引发空引用异常?这有意义吗

[Option Strict ON]

这大概是因为在VB.NET中与C#中的
null
不完全相同

对于值类型,
Nothing
表示该类型的默认值。对于
布尔值
,默认值为
False
,因此转换成功

值类型(如Integer或structures)与引用类型(如Form或String)之间的主要区别之一是引用类型支持空值。也就是说,引用类型变量可以不包含任何值,这意味着该变量实际上并不引用某个值。相反,值类型变量总是包含一个值。整数变量始终包含一个数字,即使该数字为零。如果将值Nothing分配给值类型变量,则值类型变量只会被分配其默认值(对于Integer,默认值为零)。在当前CLR中,无法查看整型变量并确定它是否从未被赋值-它包含零并不一定意味着它没有被赋值。

EDIT:为了进一步澄清,第二个示例在运行时抛出
NullReferenceException
的原因是CLR试图将
对象
(引用类型)取消绑定到
布尔值
。当然,这会失败,因为对象是用空引用初始化的(将其设置为
Nothing
):

请记住,正如我上面解释的,VB.NET关键字
Nothing
在引用类型方面仍然与C#中的
null
工作方式相同。这就解释了为什么会出现
NullReferenceException
,因为您试图强制转换的对象实际上是一个空引用。它根本不包含值,因此不能取消绑定为
布尔类型

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

Dim b As Boolean = DirectCast(Nothing, Boolean)

因为关键字
Nothing
(这一次,在值类型的情况下)仅表示“此类型的默认值”。如果是
布尔值
,则为
,因此强制转换是逻辑和直接的。

使用关键字(文字)
,与使用值为
的引用变量之间存在差异

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

  • 值为
    的引用变量是不同的。你没有特殊的行为

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

  • 显然,
    对象
    不会继承或实现
    布尔值
    ,除非将装箱的
    布尔值
    放入对象变量中

因此,下面的代码在运行时失败,出现了一个异常

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

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

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

字符
的意思是
可为空(of)

这里有几件事你必须意识到

第一个是其他人已经指出的:
Nothing
可以由VB编译器简单地解释为
Boolean
False
,给定适当的上下文,例如
Dim b as Boolean=Nothing

这意味着当编译器看到以下内容时:

b = DirectCast(Nothing, Boolean)
它看到一个文本(
Nothing
),还看到您希望将该文本用作
布尔值。这使它成为一个不需要动脑筋的问题

但现在你必须意识到第二件事<
对象上的code>DirectCast
本质上是一种取消装箱操作(对于值类型)。因此,从VB编译器的角度来看,需要发生的事情是:该框中必须有一个
布尔值,否则操作将失败。因为实际上盒子里什么都没有,而这一次我们实际上什么都没说,比如在
null
-它抛出了一个异常

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

bool b;
object obj = null;

b = (bool)default(bool);

b = (bool)obj;

希望这能让事情变得更清楚一些?

我发现将布尔变量与字符串“True”、“False”或“Is nothing”进行比较似乎可以确保得到正确的比较。我使用一个函数返回一个div的html字符串,其中包含一个选中或未选中单选按钮的图像,并且没有任何内容返回为false。使用variable=“True”或“False”字符串并对进行最后一次检查对解决该问题毫无帮助

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
Dim b作为布尔值=无
response.write CheckValue(b=“True”)
response.write(b=“False”)
response.write(b什么都不是)
函数CheckValue(inVal为布尔值)为字符串
如果无效,那么
返回(“
其他的
返回(“
如果结束
端函数
当与字符串进行隐式比较时,系统似乎会转换为字符串,而使用.tostring方法只会创建一个错误,同时允许最后一次比较实际与nothingDim 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