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

Tim*_*ter 23 .net c# c#-6.0

我刚刚从VS 2010升级到2015.我喜欢新的零条件运算符,也称为零传播.这样可以简化代码,例如:

string firstCustomerName = customers?[0].Name; // null if customers or the first customer is null
Run Code Online (Sandbox Code Playgroud)

另一个:

int? count = customers?[0]?.Orders?.Count();  // null if customers, the first customer, or Orders is null
Run Code Online (Sandbox Code Playgroud)

返回一个Nullable<int>偶数,Enumerable.Count返回一个int以区分有效计数和nulls之前的任何一个.这非常直观,非常有用.

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

string text = null;
bool contains = text?.IndexOf("Foo", StringComparison.CurrentCultureIgnoreCase) >= 0;
Run Code Online (Sandbox Code Playgroud)

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

Sco*_*ain 29

你实际拥有的是什么

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

并且int? >= int是完全合法的.

它被拆分的原因是运算符的文档说明"如果条件成员访问和索引操作链中的一个操作返回null,则链的其余部分执行停止.表达式中优先级较低的其他操作继续." 这意味着.?只会在"创建值"之前评估具有相同优先级或更高优先级的事物.

如果查看运算符优先级的顺序,您将看到列表中的"关系和类型测试运算符"要低得多,因此将在>=应用之前创建该值.


更新:因为它是在注释中提出的,所以这里是C#5规范部分,介绍了>=处理可空值时其他运算符的行为.我找不到C#6的文档.

7.3.7提升运营商

提升的运算符允许在非可空值类型上运行的预定义和用户定义的运算符也可以与这些类型的可空形式一起使用.提升运算符由满足特定要求的预定义和用户定义的运算符构成,如下所述:

  • 对于一元运营商
    + ++ - -- ! ~

    如果操作数和结果类型都是非可空值类型,则存在提升形式的运算符.提升形式是通过添加一个?操作数和结果类型的修饰符.如果操作数为null,则提升的运算符将生成空值.否则,提升的运算符解包操作数,应用基础运算符,并包装结果.

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

    如果操作数和结果类型都是非可空值类型,则存在提升形式的运算符.提升形式是通过添加一个?每个操作数和结果类型的修饰符.如果一个或两个操作数为空,则提升的运算符产生空值(例外是bool?类型的&和|运算符,如第7.11.3节中所述).否则,提升的运算符解包操作数,应用基础运算符,并包装结果.

  • 对于等于运算符
    == !=

    如果操作数类型都是非可空值类型并且结果类型是bool,则存在提升形式的运算符.提升形式是通过添加一个?每个操作数类型的修饰符.提升的运算符认为两个空值相等,并且空值不等于任何非空值.如果两个操作数都为非null,则提升的运算符将解包操作数并应用基础运算符以生成bool结果.

  • 对于关系运算符
    < > <= >=

    如果操作数类型都是非可空值类型并且结果类型是bool,则存在提升形式的运算符.提升形式是通过添加一个?每个操作数类型的修饰符.如果一个或两个操作数为空,则提升的运算符将生成值false.否则,提升的运算符解包操作数并应用基础运算符以产生bool结果.