繁体   English   中英

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

[英]Ternary operator associativity in C# - can I rely on it?

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

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:

条件运算符是右关联的,这意味着操作从右到左分组。 [示例:表单形式a ? 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友情提供的链接上,用一个例子表示为“条件运算符是右关联的”。 并且,正如您所建议的那样,我和其他人一致同意,您可以依赖它的事实允许更清晰的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM