以下在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?
案例。
答案 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()