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

发布于 2024-08-12 04:50:30 字数 800 浏览 7 评论 0原文

啊,你不就是喜欢三元虐待吗? :) 考虑下面的表达式:

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)

清晰简洁。但它确实取决于三元运算符结合性,就像第一种情况一样工作。括号只会把它做成意大利面条。

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

记忆之渊 2024-08-19 04:50:30

是的,你可以依赖这个(不仅在 C# 中,而且在所有(我知道的)其他语言中 (除了 PHP ... 想想)带有条件运算符),您的用例实际上是一种非常常见的做法,尽管有些人讨厌它。

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

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

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.

The relevant section in ECMA-334 (the C# standard) is 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 is evaluated as a ? b : (c ? d : e). end
example]

说不完的你爱 2024-08-19 04:50:30

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

回复:“尝试用括号写出整个内容。”

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·克尼根

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.

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

眼睛会笑 2024-08-19 04:50:30

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

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

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);
若水般的淡然安静女子 2024-08-19 04:50:30
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 提供的链接中,声明为“条件运算符是右关联的”,并附有示例。而且,正如您所建议的以及我和其他人所同意的,您可以依赖它的事实允许更清晰的代码。

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;

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. And, as you suggested and I and others agreed, the fact that you can rely on it allows clearer code.

满栀 2024-08-19 04:50:30

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

"如果条件为 true,则计算第一个表达式并成为结果;如果为 false,则计算第二个表达式并成为结果。只有两个表达式之一曾经被评估过。”

Refer to 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."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文