:(三元)运算符的好处
与标准的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()); }
所以,最后,现在的方便性(使用时间较短:?)与稍后对您(及其他人)的便利性有关。 这是一个判断的呼唤……但是和所有其他的代码格式问题一样,唯一真正的规则是保持一致,并且对于那些必须维护(或评级)你的代码的人来说,要有视觉上的礼貌。
(全部代码编译)
虽然上面的答案是有效的,我同意可读性是重要的,但还有两点需要考虑:
- 在C#6中,可以使用表达式方法。
这使得使用三元组特别简洁:
string GetDrink(DayOfWeek day) => day == DayOfWeek.Friday ? "Beer" : "Tea";
- 隐式类型转换的行为有所不同。
如果您有类型T1
和T2
都可以隐式转换为T
,那么下面不起作用:
T GetT() => true ? new T1() : new T2();
(因为编译器试图确定三元表达式的类型,而T1
和T2
之间没有转换。)
另一方面,下面的if/else
版本可以工作:
T GetT() { if (true) return new T1(); return new T2(); }
因为T1
被转换成T
, T2
被转换成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或一个额外的标志变量。