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

时间:2011-10-06 15:27:13

标签: vb.net ternary-operator

以下在VB.NET中编译(使用Option Strict On)并输出False

Dim b As Boolean? = Nothing
Dim myString = If(b, "True", "False")

为什么这样做?

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

      

    argument1 必填。布尔。确定要评估和返回的其他参数。

  • 并且没有从Boolean?Boolean的隐式转换:

    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'.
    

那么,为什么这有效呢?它是编译器中的错误(或“隐藏功能”)还是文档中的错误,Boolean?实际上是If(a, b, c)的第一个参数的有效类型?

PS:如果b ? x : y类型为b,则在C#中,bool?编译。


编辑:我reported this issue to Microsoft Connect。 MS的某位回复并确认文档将更新为包含Boolean?案例。

4 个答案:

答案 0 :(得分:4)

有两个“为什么”。为什么会这样,为什么他们这样做呢。我可以回答第一个,第二个是微软的。

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

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

或C#:

bool? b = null;
string myString = b.GetValueOrDefault() ? "True" : "False";

因此编译器本身正在为GetValueOrDefault

插入Nullable(of T)

答案 1 :(得分:2)

Docos声明:

  

使用三个参数调用的If运算符类似于IIf   功能除了它使用短路评估。一个IIf功能   总是评估它的所有三个参数,而一个If运算符   有三个参数只评估其中两个。第一个如果   计算参数,并将结果转换为布尔值True   或者是假。

评估然后再施放。

EDIT1

有趣的是,在运行时,强制转换没有抛出异常。

答案 2 :(得分:2)

保持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...

答案 3 :(得分:0)

在处理nullables时,你应该总是使用.HasValue属性而不是仅仅引用nullable。 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()