C# 中的三元运算符关联性 - 我可以依赖它吗?
Posted
技术标签:
【中文标题】C# 中的三元运算符关联性 - 我可以依赖它吗?【英文标题】:Ternary operator associativity in C# - can I rely on it? 【发布时间】:2010-12-18 07:47:57 【问题描述】:啊,你不只是喜欢一个好的三元滥用吗? :) 考虑以下表达式:
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)
简洁明了。但它确实取决于在第一种情况下工作的三元运算符关联性。括号只会把它做成意大利面。
那么 - 这是在任何地方指定的吗?没找到。
【问题讨论】:
你确定你的代码符合你的意思吗?例如。如果 obj1.Prop1 != obj2.Prop1 但 obj1.Prop1.CompareTo(obj2.Prop1) == 0,您的代码将产生 0 而不是继续检查 Prop2。是有意的吗? 仅仅因为你喜欢它的外观并不能使它正确,当然也不能使它具有可读性.. 任何其他查看该代码的人都必须至少在心理上添加括号,所以为什么不帮大家一个忙,重构那些代码行。 atzz - 值是原始类型 - 这不应该发生,除非时空发生扭曲。 Miky D - 建议?请记住,这是针对 lambda 表达式的,所以我想保持简短。此外,我将添加 cmets,它应该为任何查看代码的人澄清事情。 好吧,每种情况都不同,如果不查看其余代码,我无法提出任何明智的建议,但也许您可以创建一个执行比较的函数并在 lambda 中调用它。 “另外我会添加 cmets,这应该可以澄清事情......” 不要评论不可读的代码。使代码可读(当然在可能的情况下)。在这种情况下当然是可能的。 【参考方案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 提供的链接上,以“条件运算符是右关联的”为例,并附有示例。而且,正如你所建议的,我和其他人也同意,你可以依赖它的事实可以让代码更清晰。
【讨论】:
是的,您可以依赖条件运算符关联性。它在手册中,在 dcp 提供的链接上,以“条件运算符是右关联的”为例,并附有示例。而且,正如你所建议的,我和其他人也同意,你可以依赖它的事实可以让代码更清晰。【参考方案2】:是的,您可以依赖这个(不仅在 C# 中,而且在所有(我知道的)其他语言(except php ...有些人讨厌它。
ECMA-334(C# 标准)中的相关部分是 14.13 §3:
条件运算符是右结合的,这意味着操作是从右到左分组的。 [示例:
a ? b : c ? d : e
形式的表达式被评估为a ? b : (c ? d : e)
。结尾 例子]
【讨论】:
关于可读性的说明。任何具有函数式编程背景的人都会立即认识到这一点(它看起来几乎与 Haskell 的保护子句具有适当的格式)。因此,虽然它可能不会被普遍接受和使用,但它在某些圈子中确实是惯用的,并且在某些项目中可能非常合适。就个人而言,我在个人项目中使用它,我发现它非常比链式if
s 更具可读性,如果您看不懂,请阅读超出我的代码。
“在某些圈子[或项目]”是关键!
你不能在 PHP 中依赖它:***.com/questions/1921422/…
@Juan 什么,我应该写 PHP 很烂?这似乎有点跑题了。而且这不是很有趣……每个人都知道那个。
@Konrad:PHP 确实很烂,但您仍然在回答中提供误导性信息,因为您知道 PHP 的行为方式并非如此。【参考方案3】:
如果你不得不问,不要问。任何阅读您的代码的人都只需要一遍又一遍地经历您所做的相同过程,任何需要查看该代码的时间。调试这样的代码并不好玩。最终它还是会改为使用括号。
回复:“试着用括号写整个事情。”
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·克尼汉
【讨论】:
这是一个 lambda 表达式。恕我直言,其他方式只会稍微好一点。 完全同意。如果你要问,那就不清楚了。如果不清楚,请在它周围加上 f-ing 括号,不要再做一个聪明的程序员了。这就是最严重的错误的来源。 我不同意这是一个好方法。这不是惯用的,没有遇到过它的人需要仔细检查它以了解发生了什么。一系列 if/then 子句更加清晰。 是的,任何我不熟悉的东西,(或者太卡在我的学习方式中),都必须是“聪明”的编程...... - Vilx:为什么用 cmets 而不是括号?哪种方式更明显且最不可能导致 docs/cmets 与代码不同?【参考方案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);
【讨论】:
回复:你的最后一句话。我注意到问题不是关于评估顺序,而是关于关联性。这两件事完全不同。 我应该更清楚的是,它以一种允许以预期方式从左到右评估表达式的方式关联。【参考方案5】:参考msdn: http://msdn.microsoft.com/en-us/library/ty67wk28%28VS.80%29.aspx
“如果条件为真,第一个表达式被计算并成为结果;如果为假,第二个表达式被计算并成为结果。两个表达式中只有一个被计算。”
【讨论】:
是的,但这并没有说明关联性。 @Vilx - 你是对的,但是,在我已经给出答案之后,问题的关联性部分是在编辑过程中添加的(请参阅问题的编辑历史记录)。最初的问题是:“但这确实取决于三元运算符的优先级”。所以我的回答是基于优先级。 哇。重温旧答案? :) 无论如何,我仍然对“关联性与优先级”的事情感到困惑,所以 - 抱歉! :) Vilx - 事实上,我也欠你一个道歉。我之所以回复是因为今天有人对此投了反对票,所以我认为是您,因为您是唯一的回复。但现在我意识到你的回应是 2 年前的事了。所以我猜有人在没有提供理由的情况下投了反对票。无论如何,很抱歉造成混乱:) 不,我没有给你任何投票 - 赞成或反对。但在这里 - 投赞成票。就是这样。 :)以上是关于C# 中的三元运算符关联性 - 我可以依赖它吗?的主要内容,如果未能解决你的问题,请参考以下文章
三元?运算符与 C# 中的传统 If-else 运算符 [重复]