C#中的三元运算符关联性 – 我可以依赖它吗?

啊,你不喜欢一个好的三元滥用吗? :)考虑以下表达式:

true ? true : true ? false : false 

对于那些现在完全感到困惑的人,我可以告诉你,这个评估是真的 。 换句话说,它相当于:

 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) 

简洁明了。 但它确实取决于第三种情况下的三元运算符关联性。 括号只会使意大利面条脱离它。

那么 – 这是指定的吗? 我找不到它。

是的,您可以依赖于此(不仅在C#中,而且在所有(我知道)其他语言( 除了PHP …去图)与条件运算符)并且您的用例实际上是一种非常常见的做法,尽管有些人厌恶它。

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

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

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

回复: “尝试用括号写下整个​​事情。”

 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。

最后一点要思考,如果你的一些代码看起来很聪明:

调试是首先编写代码的两倍。 因此,如果您尽可能巧妙地编写代码,那么根据定义,您不够智能来调试它。 – Brian W. Kernighan

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

 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); 

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

“如果condition为true,则计算第一个表达式并成为结果;如果为false,则计算第二个表达式并成为结果。只评估两个表达式中的一个。”

 x = cond1 ? result1 : cond2 ? result2 : cond3 ? result3 : defaultResult; 

VS

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

我喜欢第一个。

是的,您可以依赖条件运算符关联性。 它在手册中,在dcp友情提供的链接中,用一个例子表示为“条件运算符是右关联的”。 并且,正如您所建议的那样,我和其他人一致认为,您可以依赖它的事实允许更清晰的代码。