19

啊,你不只是喜欢一个好的三元虐待吗?:) 考虑以下表达式:

true ? true : true ? false : false

对于那些现在完全困惑的人,我可以告诉你,这评估为true。换句话说,它等价于:

true ? true : (true ? false : false)

但这可靠吗?我可以确定在某些情况下它不会变成这样:

(true ? true : true) ? false : false

有人可能会说 -好吧,那就加括号或者干脆不使用它 - 毕竟,众所周知的事实是三元运算符是邪恶的!

当然,它们是,但在某些情况下它们实际上是有意义的。对于好奇的人 - 我正在编写通过一系列属性比较两个对象的代码。如果我像这样冷写它会很好:

obj1.Prop1 != obj2.Prop1 ? obj1.Prop1.CompareTo(obj2.Prop1) :
obj1.Prop2 != obj2.Prop2 ? obj1.Prop2.CompareTo(obj2.Prop2) :
obj1.Prop3 != obj2.Prop3 ? obj1.Prop3.CompareTo(obj2.Prop3) :
obj1.Prop4.CompareTo(obj2.Prop4)

简洁明了。但它确实取决于在第一种情况下工作的三元运算符关联性。括号只会把它做成意大利面。

那么 - 这是在任何地方指定的吗?我找不到它。

4

5 回答 5

24

是的,您可以依靠这个(不仅在 C# 中,而且在所有(我知道的)其他语言(除了 PHP ...... go figure)中都可以使用条件运算符)并且您的用例实际上是一种非常普遍的做法,尽管有些人讨厌它.

ECMA-334(C# 标准)中的相关部分是 14.13 §3:

条件运算符是右结合的,这意味着操作是从右到左分组的。[示例:表单的表达式a ? b : c ? d : e被评估为a ? b : (c ? d : e)。结束示例]

于 2009-11-19T14:14:04.650 回答
17

如果你必须问,不要。任何阅读您的代码的人都必须一遍又一遍地经历与您相同的过程,任何时候需要查看代码。调试这样的代码并不好玩。最终它只会被更改为使用括号。

回复: “试着用括号写整个事情。”

result = (obj1.Prop1 != obj2.Prop1 ? obj1.Prop1.CompareTo(obj2.Prop1) :
         (obj1.Prop2 != obj2.Prop2 ? obj1.Prop2.CompareTo(obj2.Prop2) :
         (obj1.Prop3 != obj2.Prop3 ? obj1.Prop3.CompareTo(obj2.Prop3) :
                                     obj1.Prop4.CompareTo(obj2.Prop4))))

澄清:

  • “如果非要问,别问。”
  • “任何人阅读你的代码......”

遵循项目中常见的约定是您如何保持一致性,从而提高可读性。认为您可以编写所有人都可以阅读的代码(包括那些甚至不了解该语言的人)是愚蠢的差事!

然而,在项目中保持一致性是一个有用的目标,不遵循项目公认的惯例会导致辩论,从而有损于解决真正的问题。那些阅读您的代码的人应该了解项目中使用的常见和公认的约定,甚至可能是直接从事该项目的其他人。如果他们不认识他们,那么他们应该学习他们并且应该知道去哪里寻求帮助。

也就是说——如果在你的项目中使用不带括号的三元表达式是一种常见且公认的约定,那么一定要使用它! 您必须提出的问题表明它在您的项目中并不常见或不被接受。 如果你想改变你项目中的约定,那么做明显明确的,将其标记为与其他项目成员讨论的内容,然后继续。这意味着使用括号或使用 if-else。

最后一点要考虑,如果您的某些代码对您来说似乎很聪明:

首先,调试的难度是编写代码的两倍。因此,如果您尽可能巧妙地编写代码,那么根据定义,您还不够聪明,无法对其进行调试。— 布赖恩·W·克尼汉

于 2009-11-19T14:15:35.113 回答
4

括号减损代码可读性的断言是错误的假设。我发现括号中的表达更加清晰。就个人而言,我会使用括号和/或重新格式化多行以提高可读性。重新格式化多行并使用缩进甚至可以消除对括号的需要。而且,是的,您可以依赖关联顺序是确定性的这一事实,从右到左。这允许表达式以预期的方式从左到右求值。

obj1.Prop1 != obj2.Prop1
     ? obj1.Prop1.CompareTo(obj2.Prop1)
     : obj1.Prop2 != obj2.Prop2
           ? obj1.Prop2.CompareTo(obj2.Prop2)
           : obj1.Prop3 != obj2.Prop3
                  ? obj1.Prop3.CompareTo(obj2.Prop3)
                  : obj1.Prop4.CompareTo(obj2.Prop4);
于 2009-11-19T14:23:21.137 回答
1

参考msdn:http: //msdn.microsoft.com/en-us/library/ty67wk28%28VS.80%29.aspx

“如果条件为真,则评估第一个表达式并成为结果;如果为假,则评估第二个表达式并成为结果。两个表达式中只有一个被评估。”

于 2009-11-19T14:16:35.860 回答
1
x = cond1 ? result1
  : cond2 ? result2
  : cond3 ? result3
  : defaultResult;

对比

if (cond1) x = result1;
else if (cond2) x = result2;
else if (cond3) x = result3;
else x = defaultResult;

我喜欢第一个。

是的,您可以依赖条件运算符关联性。它在手册中,在 dcp 提供的链接上,以“条件运算符是右关联的”为例,并附有示例。而且,正如你所建议的,我和其他人也同意,你可以依赖它的事实可以让代码更清晰。

于 2010-12-17T02:11:01.333 回答