使用条件?:(三元)运算符的好处

时间:2010-07-22 19:46:25

标签: c# conditional-operator

与标准的if-else语句相比,?:运算符的优点和缺点是什么?显而易见的是:

有条件的?:运营商

  • 处理直接价值比较和分配时更简洁,更简洁
  • 似乎没有if / else构造那样灵活

标准If / Else

  • 可以应用于更多情况(例如函数调用)
  • 通常不必要很长

根据声明,可读性似乎各不相同。在第一次接触到?:运算符后的一段时间内,我花了一些时间来精确地消化它是如何工作的。您是否会建议尽可能使用它,或者坚持if / else,因为我与许多非程序员一起工作?

17 个答案:

答案 0 :(得分:119)

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

很好的例子:

int result = Check() ? 1 : 0;

错误的例子:

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

答案 1 :(得分:50)

其他答案几乎涵盖了这一点,但“这是一个表达”并没有真正解释为什么那么有用......

在C ++和C#等语言中,您可以使用它们定义本地只读字段(在方法体内)。对于传统的if / then语句,这是不可能的,因为readonly字段的值必须在该单个语句中分配:

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

与:

不同
readonly int speed;  
if (shifKeyDown)  
    speed = 10;    // error - can't assign to a readonly
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等效更快,因此它可以帮助您更快地'grok'代码。

当然,仅仅因为它有用并不意味着在每种情况下使用是最好的。我建议只使用它来获取代码的短代码,其含义是明确的(或更清楚)使用?: - 如果你在更复杂的代码中使用它,或者在它们之间嵌套三元运算符它可以使代码非常难以阅读。

答案 2 :(得分:13)

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

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

答案 3 :(得分:12)

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

答案 4 :(得分:12)

非常酷的用法是:

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

答案 5 :(得分:6)

条件运算符非常适合短期条件,如下所示:

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

所以,最后,它是为了你现在的便利性(使用时间更短:?),以及后来对你(和其他人)的便利。这是一个判断调用...但与所有其他代码格式问题一样,唯一真正的规则是保持一致,并且对于那些必须维护(或评分!)代码的人来说,视觉上很有礼貌。

(所有代码用眼睛编译)

答案 6 :(得分:5)

使用三元运算符时要认识到的一点是表达式而不是语句。

在像scheme这样的函数式语言中,区别不存在:

(if(> a b)a b)

有条件的?:运营商 “似乎没有if / else构造那么灵活”

在函数式语言中。

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

答案 7 :(得分:5)

有时它可以使乍一看的值更易于阅读:

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

// Without
button.IsEnabled = !someControl.HasError;

答案 8 :(得分:5)

虽然上述答案有效,并且我同意可读性很重要,但还有两点需要考虑:

  1. 在C#6中,您可以使用表达式方法。
  2. 这使得使用三元组特别简洁:

    string GetDrink(DayOfWeek day) 
       => day == DayOfWeek.Friday
          ? "Beer" : "Tea";
    
    1. 当涉及隐式类型转换时,行为会有所不同。
    2. 如果您的类型T1T2都可以隐式转换为T,则以下工作:

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

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

      另一方面,下面的if/else版本确实有效:

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

      因为T1已转换为T,因此T2

答案 9 :(得分:4)

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

您可能感兴趣的是?? operator

答案 10 :(得分:4)

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

答案 11 :(得分:4)

如果/ else逻辑,我建议将三元(?:)运算符的使用限制为简单的单行赋值。类似这种模式的东西:

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

可以轻松转换为:

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

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

答案 12 :(得分:2)

我最常发现自己使用它的场景是默认值,尤其是返回值

return someIndex < maxIndex ? someIndex : maxIndex;

这些是我觉得很好的唯一地方,但对我们来说,我确实很喜欢。

虽然如果你正在寻找一个布尔值,这有时可能看似合适:

bool hey = whatever < whatever_else ? true : false;

因为它易于阅读和理解,但这个想法应该总是被抛到更明显的位置:

bool hey = (whatever < whatever_else);

答案 13 :(得分:2)

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

在相关的说明中,&amp;&amp;和||运算符允许使用if-then-else更难实现的一些执行模式。例如,如果一个函数有多个函数可以调用并希望执行一段代码,如果它们中的任何一个失败,那么可以使用&amp;&amp;运营商。不使用该运算符执行此操作将需要冗余代码,goto或额外的标志变量。

答案 14 :(得分:2)

如果您需要在相同条件下使用多个分支,请使用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;

用if做这件事非常麻烦:

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

您不能将初始化放在if / else中,因为它会更改范围。但引用和const变量只能在初始化时绑定。

答案 15 :(得分:2)

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

答案 16 :(得分:1)

使用 C#7 ,您可以使用新的ref locals功能来简化ref兼容变量的条件分配。那么现在,您不仅可以这样做:

int i = 0;

T b = default(T), c = default(T);

// initialization of C#7 'ref-local' variable using a conditional r-value⁽¹⁾

ref T a = ref (i == 0 ? ref b : ref c);

......但也非常精彩:

// assignment of l-value⁽²⁾ conditioned by C#7 'ref-locals'

(i == 0 ? ref b : ref c) = a;

该行代码会将a的值分配给bc,具体取决于i的值。


<小时/> 备注
1. r-value是作业的右侧 - 手侧,即分配的值。
2. l-value是作业的 - 手侧,即接收指定值的变量。