:(三元)运算符的好处

与标准的if-else语句相比,?:操作符有什么好处和缺点? 显而易见的是:

有条件的:操作员

  • 处理直接价值比较和分配时更短,更简洁
  • 似乎不像if / else结构那样灵活

标准如果/否

  • 可以应用于更多的情况(如函数调用)
  • 往往是不必要的长

可读性似乎根据声明而有所不同。 在第一次接触到?:操作符之后的一段时间,我花了一些时间来消化它的工作原理。 你会推荐在任何可能的地方使用它,或者坚持if / else,因为我和很多非程序员一起工作?

我基本上建议只有当结果语句非常短时才使用它,并且在不牺牲可读性的情况下,在简洁性方面比if / else语句显着增加。

很好的例子:

 int result = Check() ? 1 : 0; 

不好的例子:

 int result = FirstCheck() ? 1 : SecondCheck() ? 1 : ThirdCheck() ? 1 : 0; 

其他答案已经涵盖了这个问题,但“这是一个表达式”并不能真正解释为什么这么有用。

在像C ++和C#这样的语言中,可以使用它们定义局部常量(在方法体内)。 这是传统的if / then语句不可能的,因为const的值必须在单个语句中分配:

 const int speed = (shiftKeyDown) ? 10 : 1; 

不一样:

 const int speed; if (shifKeyDown) speed = 10; // error - can't assign to a const else speed = 1; // error 

以类似的方式,您可以在其他代码中嵌入第三级表达式。 除了使源代码更紧凑(因此在某些情况下更易读),它还可以使生成的机器代码更加紧凑和高效:

 MoveCar((shiftKeyDown) ? 10 : 1); 

…可能产生的代码少于两次调用相同的方法:

 if (shiftKeyDown) MoveCar(10); else MoveCar(1); 

当然,这也是一个更方便和简洁的形式(少打字,少重复,如果你必须在if / else中重复代码块,可以减少错误的机会)。 在这样干净的“常见模式”情况下:

 object thing = (reference == null) ? null : reference.Thing; 

…阅读/解析/理解(一旦你习惯了)比仅仅是啰嗦的if / else相当快,所以它可以帮助你更快速地修改代码。

当然,仅仅因为它是有用的 ,并不意味着它在每一种情况下都是最好的。 我建议只使用它的短代码的意思是明确的(或更明确)通过使用?: – 如果你使用它在更复杂的代码,或嵌套三元操作符在彼此之内,它可以使代码非常困难读书。

我通常选择一个三元运算符,否则我会有很多重复的代码。

 if (a > 0) answer = compute(a, b, c, d, e); else answer = compute(-a, b, c, d, e); 

用三元运算符,可以用下面的方法来完成。

 answer = compute(a > 0 ? a : -a, b, c, d, e); 

一个非常酷的用法是:

 x = foo ? 1 : bar ? 2 : baz ? 3 : 4; 

如果我想将变量设置为请求中发送的值(如果已定义),或者设置为某个默认值(如果未定义),那么我发现在进行Web开发时特别有用。

条件运算符对于短期条件非常有用,如下所示:

 varA = boolB ? valC : valD; 

我偶尔会使用它,因为用这种方式编写的东西花费的时间更少……不幸的是,这种分支有时会被其他开发者忽略掉。 另外,代码通常不是那么简短,所以我通常会通过把可读性提高到“ 和:在单独的行上,像这样:

 doSomeStuffToSomething(shouldSomethingBeDone() ? getTheThingThatNeedsStuffDone() : getTheOtherThingThatNeedsStuffDone()); 

然而,使用if / else块(为什么我更喜欢它们)的一个很大的好处是,稍后进入并向分支添加一些额外的逻辑是比较容易的,

 if (shouldSomethingBeDone()) { doSomeStuffToSomething(getTheThingThatNeedsStuffDone()); doSomeAdditionalStuff(); } else { doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone()); } 

或添加另一个条件:

 if (shouldSomethingBeDone()) { doSomeStuffToSomething(getTheThingThatNeedsStuffDone()); doSomeAdditionalStuff(); } else if (shouldThisOtherThingBeDone()){ doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone()); } 

所以,最后,现在的方便性(使用时间较短:?)与稍后对您(及其他人)的便利性有关。 这是一个判断的呼唤……但是和所有其他的代码格式问题一样,唯一真正的规则是保持一致,并且对于那些必须维护(或评级)你的代码的人来说,要有视觉上的礼貌。

(全部代码编译)

虽然上面的答案是有效的,我同意可读性是重要的,但还有两点需要考虑:

  1. 在C#6中,可以使用表达式方法。

这使得使用三元组特别简洁:

 string GetDrink(DayOfWeek day) => day == DayOfWeek.Friday ? "Beer" : "Tea"; 
  1. 隐式类型转换的行为有所不同。

如果您有类型T1T2都可以隐式转换为T ,那么下面不起作用:

 T GetT() => true ? new T1() : new T2(); 

(因为编译器试图确定三元表达式的类型,而T1T2之间没有转换。)

另一方面,下面的if/else版本可以工作:

 T GetT() { if (true) return new T1(); return new T2(); } 

因为T1被转换成TT2被转换成T

在使用三元运算符时,要认识到这是一个表达式,而不是一个声明。

在像方案这样的功能性语言中,这个区别不存在:

(如果(> ab)ab)

有条件的?:运算符“似乎不像if / else结构那么灵活”

在功能语言中是这样的。

当使用命令式语言进行编程时,我会在通常使用表达式(赋值,条件语句等)的情况下应用三元运算符。

有时它可以使乍一看更容易阅读布尔值的分配:

 // With button.IsEnabled = someControl.HasError ? false : true; // Without button.IsEnabled = !someControl.HasError; 

如果我设置了一个值,而且我知道这将始终是一行代码,我通常使用三元(条件)运算符。 如果有机会,我的代码和逻辑将在未来发生变化,我使用if / else,因为其他程序员更清楚。

你更感兴趣的可能是? 操作员 。

条件运算符的优点是它是一个运算符。 换句话说,它返回一个值。 由于if是一个语句,它不能返回一个值。

我建议限制使用三元(?:)运算符来简化单线赋值if / else逻辑。 类似于这种模式的东西:

 if(<boolCondition>) { <variable> = <value>; } else { <variable> = <anotherValue>; } 

可以很容易地转换为:

 <variable> = <boolCondition> ? <value> : <anotherValue>; 

我会避免在需要if / else if / else的情况下使用三元运算符,if / else嵌套或导致多行评估的if / else分支逻辑。 在这些情况下应用三元运算符可能会导致无法读取,令人困惑和无法管理的代码。 希望这可以帮助。

有一些使用的性能好处? 运营商在例如。 MS Visual C ++,但这是一个真正的编译器特定的事情。 在某些情况下,编译器实际上可以优化条件分支。

我最习惯使用它的场景是用于违约值,特别是在回报中

 return someIndex < maxIndex ? someIndex : maxIndex; 

那些确实是我觉得很好的唯一的地方,但是对他们来说我是这么做的。

尽管如果你正在寻找一个布尔值,这有时看起来像是一个合适的事情:

 bool hey = whatever < whatever_else ? true : false; 

因为阅读和理解起来非常容易,但是这个想法总是应该被抛在一个更明显的位置:

 bool hey = (whatever < whatever_else); 

如果您需要在同一条件下有多个分支,请使用if:

 if (A == 6) f(1, 2, 3); else f(4, 5, 6); 

如果你需要多个条件不同的分支,那么如果语句数量会增加,那么你会想要使用三元组:

 f( (A == 6)? 1: 4, (B == 6)? 2: 5, (C == 6)? 3: 6 ); 

另外,您可以在初始化中使用三元运算符。

 const int i = (A == 6)? 1 : 4; 

这样做是非常麻烦的:

 int i_temp; if (A == 6) i_temp = 1; else i_temp = 4; const int i = i_temp; 

你不能把初始化放在if / else中,因为它改变了范围。 但引用和常量变量只能在初始化时绑定。

三元运算符可以包含在右值内,而if-then-else则不能; 另一方面,if-then-else可以执行循环和其他语句,而三元运算符只能执行(可能是无效的)右值。

在相关说明中,&&和|| 运算符允许一些难以用if-then-else实现的执行模式。 例如,如果有几个函数调用并希望执行一段代码(如果其中任何一个失败),则可以使用&&运算符很好地完成。 如果没有这个操作符,将会需要多余的代码,一个goto或一个额外的标志变量。