C# 合并运算符

4
以下代码为什么返回false?
public static void Main()
{
    bool? someCondition = true;
    bool someConditionOverride = false;


    bool? result = someCondition ?? someConditionOverride ? false : (bool?)null;

    Console.WriteLine(result);
}

我本以为结果会是true,因为someCondition不是null,并且??运算符将返回true。然而,看起来右操作数先被计算,而左部分被简单地忽略了。

加括号可以解决混淆:

bool? result = someCondition ?? (someConditionOverride ? false : (bool?)null)

结果将是true。但我仍然好奇为什么第一个示例中左侧部分被忽略了。


C#空值合并运算符(??)的运算符优先级是多少?解释了它...可能可以作为重复使用。 - Alexei Levenkov
这其实是一个非常好的问题。 - user1017882
仅从表达式中阅读,我会期望??首先被计算,因此返回false。就像我不会期望+优先于-一样,我也不会期望?:具有更高的优先级。 - Panagiotis Kanavos
我很想了解你的条件变量实际上是什么语义;这是一个不寻常的条件表达式,我对它解决的真正问题没有任何直觉。 - Eric Lippert
1个回答

17
“左侧部分被简单忽略”?您认为这有多大可能性呢?
操作符优先级规定您的第一个版本将被解析为:
bool? result = (someCondition ?? someConditionOverride) 
                   ? false 
                   : (bool?)null;

someCondition 不为 null,且它的值为 true。因此,该表达式的结果为 true

(someCondition ?? someConditionOverride) 

所以我们得到了?分支,整个表达式返回false,就像你告诉它的那样。

添加你添加的括号完全改变了表达式的含义。这在有限的意义上解决了你的困惑,使表达式的实际含义与你的原始意图一致;但编译器从不感到困惑。在C#中,编译器会让感到困惑。

为了减少自己的困惑,我从不依赖运算符优先级。我给每个表达式加上括号。如果我设计这门语言,语法将要求这样做(除非Eric来并告诉我为什么这实际上并不是一个好主意,出于某些原因,Eric解释后我将完全理解)。

更新:预测成立:Eric来了,并说太多人会觉得强制加括号在a + b * c之类的表达式上太荒谬了,如果允许这样,就没有合理的定义例外的方式。嗯,如果他们不能容忍被强迫给每个表达式加括号,那么无论我认为他们应该怎样做,他们都不会这样做。


4
在C#中,“编译器让你感到困惑”-仅仅因为这一点就给它加1分! - Matt Hogan-Jones
2
我会投票支持“我给所有东西加上括号。如果我设计这门语言,语法就必须要求这样做。” 这就是故事的精髓。 - Artem
5
这是一个棘手的设计问题。我认为大多数人会同意,要求在a + b * c中使用括号是太重的负担。如果我们打算制定优先级(和结合律)规则,那么问题是什么规则?这对于我们从小就没有接受过训练的运算符来说尤其困难。人们可能不知道a ?? b + c ?? d(a??b) + (c??d)还是a??(b+c)??d,我们的直觉不能引导我们偏向任何一种方式。(它是后者。) - Eric Lippert
3
@EricLippert 谢谢。说实话,我确实会在 a + (b * c) 周围加上括号,而且个人并不觉得这是一个负担。在我看来,这就像是给单行 if 语句加上大括号一样。虽然我猜我不太可能说服别人。 - 15ee8f99-57ff-4f92-890c-b56153
2
@EdPlunkett:问题不是“如果Ed喜欢这样做,我们应该禁止他吗?”显然不是!你就是你。而是“我们是否应该要求每个人都像Ed一样对过度使用括号持宽容态度?”我认为这会引起很多无谓的争论。话虽如此,有些语言在优先级或关联性难以理解时需要使用括号,我认为这方面也有一定的价值。 - Eric Lippert
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接