简体   繁体   English

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

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

Ahh, don't you just love a good ternary abuse? 啊,你不喜欢一个好的三元滥用吗? :) Consider the following expression: :)考虑以下表达式:

true ? true : true ? false : false

For those of you who are now utterly perplexed, I can tell you that this evaluates to true . 对于那些现在完全感到困惑的人,我可以告诉你,这个评估是真的 In other words, it's equivalent to this: 换句话说,它等同于:

true ? true : (true ? false : false)

But is this reliable? 但这可靠吗? Can I be certain that under some circumstances it won't come to this: 我能否确定在某些情况下不会出现这种情况:

(true ? true : true) ? false : false

Some might say - well, just add parenthesis then or don't use it altogether - after all, it's a well known fact that ternary operators are evil! 有些人可能会说 - 好吧,只需添加括号或完全不使用它 - 毕竟,众所周知,三元运算符是邪恶的!

Sure they are, but there are some circumstances when they actually make sense. 当然它们是,但在某些情况下它们确实有意义。 For the curious ones - I'm wring code that compares two objects by a series of properties. 对于好奇的 - 我正在拧干通过一系列属性比较两个对象的代码。 It would be pretty nice if I cold write it like this: 如果我像这样冷写它会很好:

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)

Clear and concise. 简洁明了。 But it does depend on the ternary operator associativity working like in the first case. 但它确实取决于三元运算符的相关性,就像第一种情况一样。 Parenthesis would just make spaghetti out of it. 括号只会使意大利面条脱离它。

So - is this specified anywhere? 那么 - 这是指定的吗? I couldn't find it. 我找不到它。

Yes, you can rely on this (not only in C# but in all (that I know) other languages ( except PHP … go figure) with a conditional operator) and your use-case is actually a pretty common practice although some people abhor it. 是的,您可以依赖于此(不仅在C#中,而且在所有(我知道)其他语言( 除了PHP ...去图)与条件运算符)并且您的用例实际上是一种非常常见的做法,尽管有些人厌恶它。

The relevant section in ECMA-334 (the C# standard) is 14.13 §3: ECMA-334(C#标准)中的相关部分是14.13§3:

The conditional operator is right-associative, meaning that operations are grouped from right to left. 条件运算符是右关联的,这意味着操作从右到左分组。 [Example: An expression of the form a ? b : c ? d : e [示例:表单形式a ? b : c ? d : e a ? b : c ? d : e a ? b : c ? d : e is evaluated as 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) end example] 最后的例子]

If you have to ask, don't. 如果你不得不问,不要。 Anyone reading your code will just have to go through the same process you did, over and over again, any time that code needs to be looked at. 任何人阅读你的代码将不得不经过你做了同样的过程,一遍又一遍,需要在来看待该代码的任何时间。 Debugging such code is not fun. 调试这样的代码并不好玩。 Eventually it'll just be changed to use parentheses anyway. 最终它只会被改为使用括号。

Re: "Try to write the whole thing WITH parentheses." 回复: “尝试用括号写下整个​​事情。”

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

Clarification: 澄清:

  • "If you have to ask, don't." “如果不得不问,不要。”
  • "Anyone reading your code..." “任何人都在阅读你的代码...”

Following the conventions common in a project is how you maintain consistency, which improves readability. 遵循项目中常见的约定是如何保持一致性,从而提高可读性。 It would be a fool's errand to think you can write code readable to everyone—including those who don't even know the language! 认为你可以编写每个人都可读的代码 - 包括那些甚至不懂语言的人 - 这是一个愚蠢的错误!

Maintaining consistency within a project, however, is a useful goal, and not following a project's accepted conventions leads to debate that detracts from solving the real problem. 但是,保持项目的一致性是一个有用的目标,并且不遵循项目的公认惯例会导致辩论减少解决实际问题。 Those reading your code are expected to be aware of the common and accepted conventions used in the project, and are even likely to be someone else working directly on it. 那些阅读代码的人应该知道项目中使用的常见和接受的约定,甚至可能是直接在其上工作的其他人。 If they don't know them, then they are expected to be learning them and should know where to turn for help. 如果他们不了解他们,那么他们应该学习它们,并且应该知道在哪里寻求帮助。

That said—if using ternary expressions without parentheses is a common and accepted convention in your project, then use it, by all means! 也就是说 - 如果使用没有括号的三元表达式是项目中常见且被接受的约定,那么一定要使用它! That you had to ask indicates that it isn't common or accepted in your project. 您必须要求表明它在您的项目中不常见或被接受。 If you want to change the conventions in your project, then do the obviously unambiguous, mark it down as something to discuss with other project members, and move on. 如果你想改变你的项目中的约定,那么明确地明确无误,将其标记为与其他项目成员讨论的内容,然后继续。 Here that means using parentheses or using if-else. 这意味着使用括号或使用if-else。

A final point to ponder, if some of your code seems clever to you: 最后一点要思考,如果你的一些代码看起来很聪明:

Debugging is twice as hard as writing the code in the first place. 调试的难度是首先编写代码的两倍。 Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. 因此,如果您尽可能巧妙地编写代码,那么根据定义,您不够聪明,无法对其进行调试。 — Brian W. Kernighan - Brian W. Kernighan

The assertion that parentheses detract from the readability of the code is a false assumption. 括号中有损于代码可读性的断言是错误的假设。 I find the parenthetical expression much more clear. 我发现括号表达式更清晰。 Personally, I would use the parentheses and/or reformat over several lines to improve readability. 就个人而言,我会使用括号和/或重新格式化几行来提高可读性。 Reformatting over several lines and using indenting can even obviate the need for parentheses. 重新格式化多行并使用缩进甚至可以消除对括号的需要。 And, yes, you can rely on the fact that the order of association is deterministic, right to left. 而且,是的,你可以依赖于这样一个事实,即关联的顺序是确定性的,从右到左。 This allows the expression to evaluate left to right in the expected fashion. 这允许表达式以预期的方式从左到右进行评估。

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

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

"If condition is true, first expression is evaluated and becomes the result; if false, the second expression is evaluated and becomes the result. Only one of two expressions is ever evaluated." “如果condition为true,则计算第一个表达式并成为结果;如果为false,则计算第二个表达式并成为结果。只评估两个表达式中的一个。”

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

vs VS

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

I like the first one. 我喜欢第一个。

Yes, you can rely on conditional operator associativity. 是的,您可以依赖条件运算符关联性。 Its in the manual, at the link kindly provided by dcp, stated as "The conditional operator is right-associative", with an example. 它在手册中,在dcp友情提供的链接上,用一个例子表示为“条件运算符是右关联的”。 And, as you suggested and I and others agreed, the fact that you can rely on it allows clearer code. 并且,正如您所建议的那样,我和其他人一致同意,您可以依赖它的事实允许更清晰的代码。

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

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