【问题标题】:When using a null conditional operator in a conditional statement, how is the null case handled?在条件语句中使用空条件运算符时,空情况如何处理?
【发布时间】:2019-07-12 12:25:59
【问题描述】:

假设我在这里有以下代码:

static void Main(string[] args)
{
   StringBuilder[] s = new StringBuilder[3];
   if (s[0]?.Length > 0)
   {
       Console.WriteLine("hi");
   }
}

我的理解是 if 语句中的表达式必须是布尔表达式。布尔表达式(我的理解可能是错误的)是一个计算结果为真或假的表达式。

在这种情况下,空条件运算符将返回空值,因为引用类型变量数组中元素的默认值为空值。因此,这个 if 语句等价于

bool? x = null;
if (x)
{ 
   // do cool things here */ 
}

但这给了我一个语法错误:无法将 null 转换为 bool。

因此,上面的 StringBuilder 示例如何工作?我的理解是,上面代码的更好方法应该是将它与 null-coalescing 运算符结合起来,如下所示:

if (s[0]?.Length > 0 ?? false) {}

谢谢大家:)

【问题讨论】:

  • 我希望你已经回答了你的问题。

标签: c# .net


【解决方案1】:

在你的声明中

if (x)

x 不是 布尔表达式 它是一个 Nullable bool。简而言之,您不能将不计算结果为 布尔表达式 的语句放入 if 语句中。

但是,您可以通过指定truefalseLift,这利用了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 int 它得到检查 null 并提升到 int 进行比较

注意:重新解释后实际生成的 IL 看起来像这样

if ((object)obj == null || obj.Length <= 0)

即使生成的代码违反直觉,liftingNullable-Types 的特例,编译器对各种转换和运算符的处理方式不同

您可以通过阅读关于提升运算符提升转换Standard ECMA-334 5th Edition specifications了解更多信息

12.4.8 提升运营商

提升运算符允许预定义和用户定义的运算符 对不可为空的值类型进行操作,也可以与可空值一起使用 这些类型的形式。提升运算符是从预定义的 和满足特定要求的用户定义运算符,如 如下所述

【讨论】:

  • 抱歉,“Length(即int)被解释为Nullable int”不正确。
  • @Enigmativity 对不起,我把评论弄糊涂了,无论如何我喜欢你的回答,点赞
【解决方案2】:

你的等价是错误的。

var x = s[0]?.Length &gt; 0;bool x = false一样,不是bool? x = null

生成的未优化 IL 为:

IL_0013: ldloc.0 // 秒 IL_0014:ldc.i4.0 IL_0015:ldelem.ref IL_0016:重复 IL_0017: brtrue.s IL_001D IL_0019:流行 IL_001A:ldc.i4.0 IL_001B: br.s IL_0025 IL_001D:调用 System.Text.StringBuilder.get_Length IL_0022:ldc.i4.0 IL_0023:cgt IL_0025: stloc.1 // x

s[0] 是“true,不是null,或非零”时,brtrue.s 行只是分支,因此跳转到将.Length0 进行比较的代码 - 否则它会命中br.s 分支,它只是跳转到将结果设置为 false 的代码。

因此它相当于bool x = false 而不是bool? x = null

我的理解是 if 语句中的表达式必须是布尔表达式。布尔表达式(我的理解可能是错误的)是一个计算结果为真或假的表达式。

你的理解是正确的。

代码在 ILSpy 中反编译为:

StringBuilder[] array = new StringBuilder[3];
StringBuilder obj = array[0];
if (obj != null && obj.Length > 0)
{
    Console.WriteLine("hi");
}

【讨论】:

    【解决方案3】:

    叹息,我相信更多的谷歌搜索已经给了我一个答案! 这里的这个问题帮助了我:Trying to understand ?. (null-conditional) operator in C#

    基本上,对于某些运算符(我相信 、=),这些运算符被“解除”以处理 null 情况。如果这些二元运算符中的任何一个操作数为 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。

    谢谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-25
      • 1970-01-01
      • 2017-10-01
      • 2015-06-13
      相关资源
      最近更新 更多