Преимущества использования условного: (тернарного) оператора
каковы преимущества и недостатки?: оператор в отличие от стандартного оператора if-else. Очевидные из них:
условное ?: Оператор
- короче и лаконичнее при работе с прямыми сравнениями значений и назначений
- не кажется таким гибким, как if/else construct
Стандартный If / Else
- можно применить к другие ситуации (например, вызовы функций)
- часто бывают излишне длинными
читаемость, кажется, варьируется для каждого в зависимости от оператора. На некоторое время после первого воздействия ?- оператор, мне потребовалось некоторое время, чтобы понять, как именно это работает. Вы бы рекомендовали использовать его везде, где это возможно, или придерживаться if/else, учитывая, что я работаю со многими не-программистами?
17 ответов:
Я бы в основном рекомендовал использовать его только тогда, когда результирующий оператор чрезвычайно короток и представляет собой значительное увеличение краткости по сравнению с эквивалентом if/else без ущерба для читаемости.
хороший пример:
int result = Check() ? 1 : 0;плохой пример:
int result = FirstCheck() ? 1 : SecondCheck() ? 1 : ThirdCheck() ? 1 : 0;
это в значительной степени покрыто другими ответами, но "это выражение" на самом деле не объясняет, почему это так полезно...
в таких языках, как 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);конечно, это также более удобная и лаконичная форма (меньше ввода, меньше повторений и может уменьшить вероятность ошибок, если вам нужно дублировать куски кода в если/иначе). В чистых случаях "общего шаблона", как это:
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);
условный оператор отлично подходит для короткой условий такой:
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()); }так что, в конце концов, это о удобстве для вас сейчас (короче использовать :?) и удобство для вас (и других) позже. Это решение суда... но, как и все другие проблемы с форматированием кода, единственное реальное правило-быть последовательным и быть визуально вежливым с теми, кто должен поддерживать (или оценивать!) ваш код.
(все глаза-скомпилированный код)
одна вещь, чтобы распознать при использовании тернарного оператора, что это выражение, а не оператор.
в функциональных языках, таких как scheme, различие не существует:
(Если (> a b) a b)
условное ?: Оператор "Не кажется таким гибким, как конструкция if / else"
в функциональных языках это.
при программировании на императивных языках я применяю тернарный оператор в ситуациях, когда я обычно используйте выражения (присваивание, условные операторы и т. д.).
хотя приведенные выше ответы действительны, и я согласен с тем, что читаемость важна, есть еще 2 момента для рассмотрения:
- в 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
иногда это может сделать назначение значения bool легче читать на первый взгляд:
// 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 логики ветвления, которая приводит к оценке нескольких строк. Применение тернарного оператора в этих ситуациях, скорее всего, приведет к нечитабельности, сбивает с толку, и неуправляемым кодом. Надеюсь, это поможет.
есть некоторые преимущества производительности с помощью the ? оператор в например. 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;делать это с if очень грязно:
int i_temp; if (A == 6) i_temp = 1; else i_temp = 4; const int i = i_temp;вы не можете поместить инициализацию внутри if/else, потому что она изменяет область. Но ссылки и переменные const могут быть связаны только при инициализации.
тернарный оператор может быть включен в rvalue, тогда как if-then-else не может; с другой стороны, if-then-else может выполнять циклы и другие операторы, тогда как тернарный оператор может выполнять только (возможно, void) rvalues.
в соответствующей заметке операторы && и | / допускают некоторые шаблоны выполнения, которые сложнее реализовать с помощью if-then-else. Например, если у вас есть несколько функций для вызова и вы хотите выполнить часть кода, если какой-либо из них не удастся, он может сделайте красиво с помощью оператора&&. Выполнение этого без этого оператора потребует либо избыточного кода, либо goto, либо дополнительной переменной флага.
С 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илиbилиcв зависимости от значенияi.
Примечания
1. r-значение - это право - ручная сторона назначения, значение, которое присваивается.
2. l-значение - это левый-ручная сторона присваивания, переменная, которая получает назначенное значение.
Comments