空条件运算符评估bool不bool?正如所料

时间:2016-05-17 13:07:38

标签: c# .net c#-6.0

我刚从VS 2010升级到2015年。我喜欢新的null-conditional operator,也称为零传播。这样可以简化代码,例如:

string firstCustomerName = customers?[0].Name; // null if customers or the first customer is null
另一个:

int? count = customers?[0]?.Orders?.Count();  // null if customers, the first customer, or Orders is null
即使Nullable<int>返回Enumerable.Count以区分有效计数和之前的任何int

也会返回nulls。这非常直观且非常有用。

但是为什么这会按预期编译和工作(它返回false):

string text = null;
bool contains = text?.IndexOf("Foo", StringComparison.CurrentCultureIgnoreCase) >= 0;

它应该返回bool?(它没有)或不编译。

2 个答案:

答案 0 :(得分:29)

你实际拥有的是

string text = null;
int? index = text?.IndexOf("Foo", StringComparison.CurrentCultureIgnoreCase);
bool contains = index >= 0;

int? >= int完全合法。

它被分割的原因是the documentation for the operator个状态“如果条件成员访问和索引操作链中的一个操作返回null,则链的其余部分执行停止。其他操作优先级较低在表达式中继续。“这意味着.?只会在”创建值“之前评估具有相同优先级或更高优先级的事物。

如果查看the order of operator precedence,您会看到列表中的“关系和类型测试运算符”要低得多,因此将在应用>=之前创建该值。

UPDATE:因为它是在评论中提出的,所以这里是关于>=和其他运算符在处理可空值时的行为方式的C#5规范部分。我找不到C#6的文档。

  

7.3.7解除运营商

     

提升运算符允许对非可空值类型进行操作的预定义和用户定义运算符也可以与可空字段一起使用   这些类型的形式。提升操作员是根据预定义构建的   和满足某些要求的用户定义的运算符   如下所述:

     
      
  • 对于一元运算符
         + ++ - -- ! ~

         

    如果操作数和结果类型都是非可空值类型,则存在提升形式的运算符。提升的形式是   通过添加单个构造?操作数和结果的修饰符   类型。如果操作数是,则提升的运算符产生空值   空值。否则,提升的操作员解开操作数,应用   底层运算符,并包装结果。

  •   
  • 对于二元运算符
      + - * / % & | ^ << >>

         

    如果操作数和结果类型存在运算符的提升形式   都是不可为空的值类型。提升形式由   加一个?每个操作数和结果类型的修饰符。解除了   如果一个或两个操作数为空,则运算符生成空值(an   例外是&amp;和|布尔的经营者?类型,如上所述   在§7.11.3)。否则,提升的操作员打开操作数,   应用基础运算符,并包装结果。

  •   
  • 对于平等操作员
      == !=

         

    如果操作数类型都是,则存在提升形式的运算符   不可为空的值类型,如果结果类型是bool。解除了   表单是通过添加单个?每个操作数的修饰符   类型。提升的运算符认为两个空值相等,并且为空   值不等于任何非空值。如果两个操作数都是非null,   提升的操作员解开操作数并应用底层操作   运算符产生bool结果。

  •   
  • 对于关系运营商
      < > <= >=

         

    如果操作数类型都是非可空值类型且结果类型为bool,则存在提升形式的运算符。解除了   表单是通过添加单个?每个操作数的修饰符   类型。如果一个或两个,提升的运算符产生值false   操作数为空。否则,提升的操作员解开操作数   并应用基础算子产生布尔结果。

  •   

答案 1 :(得分:3)

如果您使用此代码并将鼠标悬停在x上,则表明xint?

var x = text?.IndexOf("Foo", StringComparison.CurrentCultureIgnoreCase);
bool contains = x >= 0;

因此输入仍然正确。

然后让我们看看x >= 0:这是int? >= int。在可空和非可空结构之间有一个运算符。这就是它运作的原因。

如果您查看IL,您会看到它实际上会调用HasValueGetValueOrDefault()。我想有一个操作符这样做,但我在参考源中找不到它,所以它应该在CLR或编译器中:

instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()

...
instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()