web-dev-qa-db-fra.com

Avantages de l’utilisation de l’opérateur conditionnel?: (Ternaire)

Quels sont les avantages et les inconvénients de l'opérateur?: Par opposition à la déclaration standard if-else. Les plus évidents étant:

Conditionnel?: Opérateur

  • Plus court et plus concis lorsqu'il s'agit de comparaisons directes de valeurs et d'assignations
  • Ne semble pas être aussi flexible que la construction if/else

Standard If/Else

  • Peut être appliqué à plusieurs situations (telles que des appels de fonction)
  • sont souvent inutilement longs

La lisibilité semble varier pour chacun en fonction de la déclaration. Pendant un petit moment après avoir été exposé à l'opérateur?:, Il m'a fallu un certain temps pour digérer exactement comment cela fonctionnait. Recommanderiez-vous de l’utiliser autant que possible, ou de vous en tenir à/sinon, étant donné que je travaille avec beaucoup de non-programmeurs?

100
KChaloux

Je recommanderais en principe de ne l'utiliser que lorsque l'énoncé résultant est extrêmement court et représente une augmentation significative de la concision par rapport à l'équivalent if/else sans sacrifier la lisibilité.

Bon exemple:

int result = Check() ? 1 : 0;

Mauvais exemple:

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

Ceci est à peu près couvert par les autres réponses, mais "c'est une expression" n'explique pas vraiment pourquoi c'est si utile ...

Dans des langages tels que C++ et C #, vous pouvez définir des champs locaux en lecture seule (au sein d'un corps de méthode) à l'aide de ceux-ci. Ceci n'est pas possible avec une instruction if/then conventionnelle car la valeur d'un champ en lecture seule doit être affectée dans cette instruction unique:

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

n'est pas la même chose que:

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

De la même manière, vous pouvez incorporer une expression tertiaire dans un autre code. En plus de rendre le code source plus compact (et dans certains cas plus lisible, par conséquent), il peut également rendre le code machine généré plus compact et plus efficace:

MoveCar((shiftKeyDown) ? 10 : 1);

... peut générer moins de code que d'avoir à appeler deux fois la même méthode:

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

Bien sûr, il s’agit également d’une forme plus pratique et plus concise (moins de frappe, moins de répétition, et peut réduire le risque d’erreurs si vous devez dupliquer des morceaux de code dans un if/else). En cas de "modèle commun" propre comme ceci:

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

... il est tout simplement plus rapide de lire/analyser/comprendre (une fois que vous y êtes habitué) que l'équivalent if/else à longue portée, de sorte qu'il peut vous aider à "coder" le code plus rapidement.

Bien sûr, ce n'est pas parce que c'est utile que c'est la meilleure chose à faire d'utiliser dans tous les cas. Je conseillerais de ne l'utiliser que pour de courts morceaux de code dont le sens est clair (ou plus clair) en utilisant ?: _ Si vous l'utilisez dans un code plus complexe ou si vous utilisez des opérateurs ternaires imbriqués l'un dans l'autre, cela peut rendre le code extrêmement difficile à lire.

50
Jason Williams

En général, je choisis un opérateur ternaire alors que, sinon, il y avait beaucoup de doublons de code.

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

Avec un opérateur ternaire, ceci pourrait être accompli avec ce qui suit.

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

Je trouve cela particulièrement utile lors du développement Web si je veux définir une variable sur une valeur envoyée dans la demande si elle est définie ou sur une valeur par défaut si ce n'est pas le cas.

12
wshato

Une utilisation vraiment cool est:

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

L'opérateur conditionnel est idéal pour les conditions courtes, comme ceci:

varA = boolB ? valC : valD;

Je l'utilise parfois parce que cela prend moins de temps pour écrire quelque chose de cette façon ... malheureusement, cette branche peut parfois être manquée par un autre développeur parcourant votre code. De plus, le code n'est généralement pas si court, alors j'aide généralement à améliorer la lisibilité en mettant le? et: sur des lignes séparées, comme ceci:

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

Cependant, le gros avantage de l'utilisation de blocs if/else (et pourquoi je les préfère) est qu'il est plus facile d'entrer plus tard et d'ajouter de la logique supplémentaire à la branche,

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

ou ajouter une autre condition:

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

Donc, au final, il s’agit de commodité pour vous maintenant (plus courte à utiliser:?) Par rapport à la commodité pour vous (et les autres) plus tard. C'est une question de jugement ... mais comme tous les autres problèmes de formatage de code, la seule règle réelle est d'être cohérent et d'être visuellement courtois avec ceux qui doivent maintenir (ou noter!) Votre code.

(tout code compilé dans les yeux)

6
iandisme

Une chose à reconnaître lors de l’utilisation de l’opérateur ternaire est qu’il s’agit d’une expression et non d’une déclaration.

Dans les langages fonctionnels comme schéma, la distinction n'existe pas:

(si (> a b) a b)

Conditionnel?: Opérateur "Ne semble pas être aussi flexible que la construction if/else"

Dans les langages fonctionnels c'est.

Lors de la programmation dans des langages impératifs, j'applique l'opérateur ternaire dans des situations où j'utilisais généralement des expressions (affectation, instructions conditionnelles, etc.).

5
Ken Struys

Bien que les réponses ci-dessus soient valables, et je suis d'accord pour dire que la lisibilité est importante, il y a 2 autres points à considérer:

  1. En C # 6, vous pouvez avoir des méthodes basées sur l'expression.

Cela rend l'utilisation du ternaire particulièrement concise:

string GetDrink(DayOfWeek day) 
   => day == DayOfWeek.Friday
      ? "Beer" : "Tea";
  1. Le comportement diffère en ce qui concerne la conversion de type implicite.

Si vous avez des types T1 et T2 qui peut être converti implicitement en T, alors le sous-programme fonctionne non fonctionne:

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

(car le compilateur essaie de déterminer le type de l'expression ternaire et qu'il n'y a pas de conversion entre T1 et T2.)

D'autre part, le if/else La version ci-dessous fonctionne:

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

parce que T1 est converti en T et donc T2

5
la-yumba

Parfois, il est facile de lire au premier abord l'attribution d'une valeur bool:

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

// Without
button.IsEnabled = !someControl.HasError;
5
Tyler Pantuso

Je recommanderais de limiter l’utilisation de l’opérateur ternaire (? :) à la simple affectation d’une ligne si/d’autre. Quelque chose qui ressemble à ce modèle:

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

Pourrait être facilement converti en:

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

J'éviterais d'utiliser l'opérateur ternaire dans des situations nécessitant une logique de branche if/else if/else, imbriquée si/else ou if/else qui aboutit à l'évaluation de plusieurs lignes. L'application de l'opérateur ternaire dans ces situations aboutirait probablement à un code illisible, source de confusion et ingérable. J'espère que cela t'aides.

4
HOCA

Si je mets une valeur et que je sais que ce sera toujours une ligne de code, j'utilise généralement l'opérateur ternaire (conditionnel). S'il y a une chance que mon code et ma logique changent à l'avenir, j'utilise un if/else, car c'est plus clair pour les autres programmeurs.

L’intéressant est peut-être le opérateur ?? .

4
drharris

L'avantage de l'opérateur conditionnel est qu'il s'agit d'un opérateur. En d'autres termes, il retourne une valeur. Puisque if est une instruction, il ne peut pas renvoyer de valeur.

4
Gabe

L’utilisation de la? opérateur dans par exemple. MS Visual C++, mais c’est vraiment une chose spécifique au compilateur. Le compilateur peut réellement optimiser la branche conditionnelle dans certains cas.

2
darklon

Le scénario que je me trouve le plus souvent à l’utiliser est celui des valeurs par défaut et en particulier des retours.

return someIndex < maxIndex ? someIndex : maxIndex;

Ce sont vraiment les seuls endroits où je trouve Nice, mais pour eux, je le fais.

Cependant, si vous recherchez un booléen, cela peut parfois sembler une bonne chose à faire:

bool hey = whatever < whatever_else ? true : false;

Parce qu'il est si facile à lire et à comprendre, mais cette idée devrait toujours être considérée comme la plus évidente:

bool hey = (whatever < whatever_else);
2
Jimmy Hoffa

Si vous avez besoin de plusieurs branches dans le même cas, utilisez un if:

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

Si vous avez besoin de plusieurs branches avec des conditions différentes, alors si le nombre d'instructions est Snowball, vous voudrez utiliser le ternaire:

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

En outre, vous pouvez utiliser l'opérateur ternaire lors de l'initialisation.

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

Faire ça avec si c'est très salissant:

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

Vous ne pouvez pas placer l'initialisation dans if/else, car cela modifie l'étendue. Mais les références et les variables const ne peuvent être liées qu'à l'initialisation.

2
Ben Voigt

L'opérateur ternaire peut être inclus dans une valeur, alors qu'un if-then-else ne le peut pas; d'autre part, un if-then-else peut exécuter des boucles et d'autres instructions, tandis que l'opérateur ternaire ne peut exécuter que des valeurs rvalues ​​(éventuellement void).

Sur une note connexe, les && et || les opérateurs autorisent certains modèles d'exécution plus difficiles à implémenter avec if-then-else. Par exemple, si une personne a plusieurs fonctions à appeler et souhaite exécuter un morceau de code en cas d'échec de l'une d'entre elles, vous pouvez le faire aisément à l'aide de l'opérateur &&. Le faire sans cet opérateur nécessitera soit un code redondant, un goto ou une variable indicateur supplémentaire.

2
supercat