说我在这里有以下代码:
static void Main(string[] args)
{
StringBuilder[] s = new StringBuilder[3];
if (s[0]?.Length > 0)
{
Console.WriteLine("hi");
}
}
我的理解是if语句内的表达式必须是布尔表达式。布尔表达式(我的理解可能是错误的)是计算结果为true或false的表达式。
在这种情况下,空条件运算符将返回空值,因为引用类型变量数组中元素的默认值是空值。因此,此if语句等效于
bool? x = null;
if (x)
{
// do cool things here */
}
但这给了我一个语法错误:无法将null转换为bool。
因此,上述带有StringBuilder的示例如何运作?我的理解是,上面代码的更好方法是将其与null运算符结合使用,如:
if (s[0]?.Length > 0 ?? false) {}
谢谢:)
答案 0 :(得分:3)
在您的声明中
if (x)
{x
不是一个布尔表达式,它是一个 Nullable bool
...简而言之,您不能放置不评估为if
语句中的布尔表达式。
但是,您可以通过指定Lift
或true
false
来使用,这利用了 Nullable Lifted
运算符。例如
if (x == true)
//or
if (x == false)
类似地,提升是导致以下问题起作用的原因。
int? i = null;
if(i > 0) {...}
这也可以通过 Null-Conditional 运算符
看到if (SomeObj?.Length > 0)
这里发生的是, Null-Conditional 强制将Length
(它是int
)解释为 Nullable { {1}}被检查是否为空,并提升到int
进行比较
注意 :重新解释时实际生成的IL看起来像这样
int
即使生成的代码违反直觉,对于 Nullable-Types , lifting 也是特例,编译器对各种转换和运算符
的处理方式也有所不同通过在提升的运算符和提升转换
上浏览Standard ECMA-334 5th Edition specifications,可以了解更多信息12.4.8解除运营商
提升的运算符允许预定义和用户定义的运算符 对非可空值类型进行操作以与可空值一起使用 这些类型的形式。提升的操作员是根据预定义构造的 和满足某些要求的用户定义的运算符,例如 如下所述
答案 1 :(得分:1)
您的对等是错误的。
写作var x = s[0]?.Length > 0;
与bool x = false
相同,而不是bool? x = null
;
产生的未优化的IL是:
IL_0013: ldloc.0 // s IL_0014: ldc.i4.0 IL_0015: ldelem.ref IL_0016: dup IL_0017: brtrue.s IL_001D IL_0019: pop IL_001A: ldc.i4.0 IL_001B: br.s IL_0025 IL_001D: call System.Text.StringBuilder.get_Length IL_0022: ldc.i4.0 IL_0023: cgt IL_0025: stloc.1 // x
当brtrue.s
为“ s[0]
而不是true
或非零”时,行null
仅分支,因此跳转到比较{{1 }}与.Length
-否则,它会到达0
分支,该分支只是跳转到将结果设置为br.s
的代码。
因此,它等效于false
而不是bool x = false
我的理解是if语句内的表达式必须是布尔表达式。布尔表达式(我的理解可能是错误的)是计算结果为true或false的表达式。
您的理解正确。
代码在ILSpy中反编译为:
bool? x = null
答案 2 :(得分:-1)
叹息,我相信更多谷歌搜索为我提供了答案! 这里的问题帮助我:Trying to understand ?. (null-conditional) operator in C#
基本上,对于某些运算符(我相信<,>,<=,> =),这些运算符被“提升”以处理空值情况。如果这些二进制运算符中的任何一个操作数为null,它们将自动返回false。
例如
int? x = 5;
int? y = 10;
bool b = x < y; // true
为什么这样做?因为它在语义上等同于:
bool b = (x.HasValue && y.HasValue) ? (x.Value < y.Value) : false;
如果其中一个操作数没有值,则始终返回false。
谢谢!