Ответ 1
Утверждение, написанное в письменном виде, может быть улучшено, если его переписать следующим образом.
good = m_seedsfilter==0 ? true :
m_seedsfilter==1 ? newClusters(Sp) :
newSeed(Sp);
... но в целом вы должны просто стать знакомыми с тройственным выражением. Нет ничего злонамеренного в отношении кода, который был первоначально опубликован, или версии xanatos, или моего. Тернарные заявления не являются злыми, они являются основной чертой языка, и как только вы познакомитесь с ними, вы заметите, что такой код (как я опубликовал, а не как написано в вашем исходном сообщении) на самом деле проще чтобы читать, чем цепочку операторов if-else. Например, в этом коде вы можете просто прочитать этот оператор следующим образом: "Переменная good
равна... if m_seedsfilter==0
, затем true
, в противном случае, если m_seedsfilter==1
, тогда newClusters(Sp)
, в противном случае newSeed(Sp)
".
Обратите внимание, что моя версия выше позволяет избежать трех отдельных назначений переменной good
и дает понять, что целью оператора является присвоение значения good
. Кроме того, написанный таким образом, он дает понять, что, по сути, это конструкция "switch-case", причем по умолчанию используется newSeed(Sp)
.
Следует, наверное, отметить, что мой переписать выше хорошо, пока operator!()
для типа m_seedsfilter
не переопределяется. Если это так, то вам придется использовать это, чтобы сохранить поведение вашей оригинальной версии...
good = !m_seedsfilter ? true :
m_seedsfilter==1 ? newClusters(Sp) :
newSeed(Sp);
... и как поясняется ниже комментарий xanatos, если ваши методы newClusters()
и newSeed()
возвращают разные типы, чем другие, и если эти типы написаны с помощью тщательно продуманных бессмысленных операторов преобразования, то вы будете иметь чтобы вернуться к самому оригинальному коду (хотя, надеюсь, отформатирован лучше, как и в собственном сообщении xanatos), чтобы точно дублировать то же поведение, что и исходное сообщение. Но в реальном мире никто не собирается этого делать, поэтому моя первая версия выше должна быть в порядке.
ОБНОВЛЕНИЕ, через два с половиной года после первоначального сообщения/ответа: Интересно, что @TimothyShields и я постоянно время от времени набираю обороты, и ответ Тима, похоже, постоянно отслеживает примерно 50% этого ответа upvotes, более или менее (43 против 22 из этого обновления).
Я думал, что добавлю еще один пример ясности, которую может добавить тройной оператор при разумном использовании. Ниже приведены краткие фрагменты кода, который я писал для анализатора использования вызова (инструмент, который анализирует скомпилированный код C, но сам инструмент написан на С#). Все три варианта выполняют точно такую же цель, по крайней мере, насколько внешне видимые эффекты идут.
1. Без тернарного оператора:
Console.Write(new string(' ', backtraceIndentLevel) + fcnName);
if (fcnInfo.callDepth == 0)
{
Console.Write(" (leaf function");
}
else if (fcnInfo.callDepth == 1)
{
Console.Write(" (calls 1 level deeper");
}
else
{
Console.Write(" (calls " + fcnInfo.callDepth + " levels deeper");
}
Console.WriteLine(", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
2. С помощью тернарного оператора отдельные вызовы Console.Write():
Console.Write(new string(' ', backtraceIndentLevel) + fcnName);
Console.Write((fcnInfo.callDepth == 0) ? (" (leaf function") :
(fcnInfo.callDepth == 1) ? (" (calls 1 level deeper") :
(" (calls " + fcnInfo.callDepth + " levels deeper"));
Console.WriteLine(", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
3. С помощью тернарного оператора свернута до одного вызова Console.Write():
Console.WriteLine(
new string(' ', backtraceIndentLevel) + fcnName +
((fcnInfo.callDepth == 0) ? (" (leaf function") :
(fcnInfo.callDepth == 1) ? (" (calls 1 level deeper") :
(" (calls " + fcnInfo.callDepth + " levels deeper")) +
", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
Можно утверждать, что разница между тремя приведенными выше примерами тривиальна, и поскольку это тривиально, почему бы не предпочесть более простой (первый) вариант? Все дело в том, чтобы быть кратким; выражая идею в "как можно меньше слов", чтобы слушатель/читатель все еще мог вспомнить начало идеи к тому времени, когда я дойду до конца идеи. Когда я говорю с маленькими детьми, я использую простые, короткие предложения, и в результате для выражения идеи требуется больше предложений. Когда я говорю со взрослыми, свободно владеющими языком, я использую более длинные и более сложные предложения, которые более кратко выражают идеи.
Эти примеры печатают одну строку текста на стандартный вывод. Хотя выполняемая ими операция проста, ее легко представить как подмножество большей последовательности. Чем короче я могу четко выражать подмножества этой последовательности, тем больше эта последовательность может поместиться на экране редактора. Конечно, я могу легко занять эти усилия слишком далеко, что затрудняет понимание; цель состоит в том, чтобы найти "сладкое пятно между тем, чтобы быть понятным и кратким. Я утверждаю, что как только программист знаком с тройным выражением, понимание кода, использующего их, становится проще, чем понимание кода, который не имеет значения (например, 2 и 3), а 1).
Конечная причина, по которой опытные программисты должны чувствовать себя комфортно, используя тройные заявления, заключается в том, чтобы избежать создания ненужных временных переменных при выполнении вызовов методов. В качестве примера я представляю четвертый вариант вышеприведенных примеров с логикой, сжатой до одного вызова Console.WriteLine()
; результат будет меньше понятным и меньше лаконичным:
4. Без тернарного оператора свернута до одного вызова Console.Write():
string tempStr;
if (fcnInfo.callDepth == 0)
{
tempStr = " (leaf function";
}
else if (fcnInfo.callDepth == 1)
{
tempStr = " (calls 1 level deeper";
}
else
{
tempStr = " (calls " + fcnInfo.callDepth + " levels deeper";
}
Console.WriteLine(new string(' ', backtraceIndentLevel) + fcnName + tempStr +
", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
Прежде чем утверждать, что "конденсирование логики с одним вызовом на Console.WriteLine()
не нужно", подумайте, что это всего лишь пример: представьте вызовы на какой-то другой метод, который принимает несколько параметров, для всех из которых требуются временные состояние других переменных. Вы можете создать свои собственные временные ряды и вызвать вызов метода с этими временными или использовать тернарный оператор и позволить компилятору создавать собственные (неназванные) временные ряды. Опять же я утверждаю, что тернарный оператор допускает гораздо более сжатый и понятный код, чем без. Но для того, чтобы это было понятно, вам придется отказаться от любых предвзятых понятий, которые у вас есть, что тернарный оператор злой.