为什么VB.NET中的三元运算符接受可为空的布尔值?

为什么VB.NET中的三元运算符接受可为空的布尔值?,vb.net,ternary-operator,Vb.net,Ternary Operator,以下内容在VB.NET中编译(选项Strict On)并输出False: Dim b As Boolean? = Nothing Dim myString = If(b, "True", "False") 为什么会这样 明确指出,If的三参数版本需要一个Boolean作为第一个参数: 需要论证1。布尔型。确定要计算和返回的其他参数 而且没有从布尔值?到布尔值的隐式转换: Dim b1 As Boolean? = Nothing Dim b2 As Boolean = b1 ' Fail

以下内容在VB.NET中编译(选项Strict On)并输出
False

Dim b As Boolean? = Nothing
Dim myString = If(b, "True", "False")
为什么会这样

  • 明确指出,
    If
    的三参数版本需要一个
    Boolean
    作为第一个参数:

    需要论证1。布尔型。确定要计算和返回的其他参数

  • 而且没有从
    布尔值?
    布尔值的隐式转换:

    Dim b1 As Boolean? = Nothing
    Dim b2 As Boolean = b1   ' Fails with the following error:
                             '   Option Strict On disallows implicit conversions
                             '   from 'Boolean?' to 'Boolean'.
    
那么,为什么会这样呢?它是编译器中的错误(或“隐藏功能”),还是文档中的错误,并且
布尔值?
实际上是
的第一个参数的有效类型,如果(a,b,c)

附言:在C#中,
b?如果
b
类型为
bool?
,则x:y
不会编译


编辑:我已经完成了。MS的人员已回复并确认文档将更新为包含
Boolean?
案例。

Docos声明:

使用三个参数调用的If运算符的工作方式与IIf类似 功能,但它使用短路评估。IIf函数 始终计算其所有三个参数,而If运算符 它有三个参数,只计算其中的两个。第一个如果 参数进行求值,结果转换为布尔值True 或者是假的

它进行求值,然后进行强制转换

EDIT1


有趣的是,在运行时,cast没有抛出异常

处理可空值时,应始终使用.HasValue属性,而不仅仅是引用可空值。VB在检查对象是否已实例化时使用了以下语法:

If Foo Then
  ' Is instantiated
End If
因此,您的示例允许评估三元If。在这种情况下,我建议您将代码“修复”得更明确一些:

Dim b As Boolean? = Nothing 
Dim myString = If(b.HasValue, "True", "False") 
或者,与其使用三元If,不如将其改写为:

Dim myString = b.GetValueOrDefault(False).ToString()
有两个“为什么”。为什么会这样,为什么他们会这样做。我可以回答第一个,第二个是微软的

如果使用Reflector检查从VB.Net生成的代码,您将看到:

Dim b As Nullable(Of Boolean) = Nothing
Dim myString As String = IIf(b.GetValueOrDefault, "True", "False")
或C#:


因此,编译器本身正在为
null(of T)

插入
GetValueOrDefault
,让ildasm.exe在遇到类似问题时随时可用。编译器使用Nullable(Of T).GetValueOrDefault()。官方语言规范并不禁止这样做。另外,这也不能说明这一点,这并不罕见

  IL_0001:  ldloca.s   b
  IL_0003:  initobj    valuetype [mscorlib]System.Nullable`1<bool>
  IL_0009:  ldloca.s   b
  IL_000b:  call       instance !0 valuetype [mscorlib]System.Nullable`1<bool>::GetValueOrDefault()
  IL_0010:  brtrue.s   IL_0019
  etc...
IL_0001:ldloca.s b
IL_0003:initobj valuetype[mscorlib]系统。可为null`1
IL_0009:ldloca.s b
IL_000b:调用实例!0 valuetype[mscorlib]系统。可为null的`1::GetValueOrDefault()
IL_0010:brtrue.s IL_0019
等

它真的使用IIF吗?(注意两个I)?接得好。我的Reflector被设置为.NET2.0,它没有VB
IF
trialer操作符。更新到4.0使其成为
IF
而不是
IFF
。显然,这是Reflector试图从IL重建VB.Net。实际的IL命令是
brtrue.s
,它是“branch if true”,这是三元运算通常转换为的。计算第一个if参数,并将结果转换为布尔值
。。。漂亮的斑点!有趣的是,这似乎不是真的:
如果(0,1,2)
抛出
选项Strict On,则不允许从“整数”到“布尔”的隐式转换。
,因此第一个参数并不总是转换为布尔值。
  IL_0001:  ldloca.s   b
  IL_0003:  initobj    valuetype [mscorlib]System.Nullable`1<bool>
  IL_0009:  ldloca.s   b
  IL_000b:  call       instance !0 valuetype [mscorlib]System.Nullable`1<bool>::GetValueOrDefault()
  IL_0010:  brtrue.s   IL_0019
  etc...