Intereting Posts

Разумный или нет: несколько тернарных операторов C # + Бросок, если невозможен

Вы находите следующий код C # parsingчивым?

private bool CanExecuteAdd(string parameter) { return this.Script == null ? false : parameter == "Step" ? true : parameter == "Element" ? this.ElementSelectedInLibrary != null && this.SelectedStep != null : parameter == "Choice" ? this.SelectedElement != null : parameter == "Jump" ? this.SelectedStep != null : parameter == "Conditional jump" ? false : false.Throw("Unknown Add parameter {0} in XAML.".F(parameter)); } 

где Throw определяется как:

 public static T Throw(this T ignored, string message) { throw new Exception(message); } 

Я знаю, что это не идиоматический C #. Однако, вы могли бы понять это с первого взгляда или второго взгляда? Или я слишком далеко зашел?

Я использовал такой код на Java в достаточной степени. Мне не нравится бит false.Throw , но с несколькими условностями, подобными этому (в частности, отформатирован таким образом), на мой взгляд.

Это немного странно в первый раз, когда вы его видите, но после этого это просто удобный образец, о котором нужно знать.

Одна из альтернатив использования false.Throw здесь будет примерно такой:

 bool? ret = this.Script == null ? false : parameter == "Step" ? true : parameter == "Element" ? this.ElementSelectedInLibrary != null && this.SelectedStep != null : parameter == "Choice" ? this.SelectedElement != null : parameter == "Jump" ? this.SelectedStep != null : parameter == "Conditional jump" ? false : null; if (ret == null) { throw new ArgumentException( string.Format("Unknown Add parameter {0} in XAML.", parameter); } return ret.Value; 

EDIT: На самом деле, в этом случае я бы не использовал либо if / else, либо этот шаблон … Я бы использовал switch / case. Это может быть очень компактным, если вы хотите:

 if (this.Script == null) { return false; } switch (parameter) { case "Step": return true; case "Element": return this.ElementSelectedInLibrary != null && this.SelectedStep != null; case "Choice": return this.SelectedElement != null; case "Jump": return this.SelectedStep != null; default: throw new ArgumentException( string.Format("Unknown Add parameter {0} in XAML.", parameter); } 

Почему бы не использовать переключатель? Я думаю, что это более читаемо.

 private bool CanExecuteAdd(string parameter) { if (Script == null) return false; switch (parameter) { case "Step": return true; case "Element": return ElementSelectedInLibrary != null && SelectedStep != null; case "Choice": return SelectedElement != null; case "Jump": return SelectedStep != null; case "Conditional jump": return false; default: throw new Exception(string.Format("Unknown Add parameter {0} in XAML.", parameter)); } } 

Мое правило: используйте выражения для вещей без побочных эффектов. Используйте утверждения для вещей с одним побочным эффектом и для streamа управления.

Бросок – фактически побочный эффект; он не вычисляет значение, он изменяет stream управления. Вы вычисляете ценность, вычисления, вычисления, вычисления, а затем стрелу, побочный эффект. Я нахожу код таким запутанным и досадным. Я говорю, что stream управления должен быть в операторах, а не в побочном эффекте того, что выглядит как вычисление.

Я голосую за непонятные.

Хотя синтаксис верен, он несколько запутан, и, поскольку это не так, смею сказать, «традиционный», многим разработчикам придется тратить время, пытаясь понять, что они читают. Не идеальная ситуация.

Считываемость определенно является одним из ключевых компонентов хорошего кодирования, и я бы сказал, что ваш образец не сразу читается для большинства разработчиков.

Мне нравится условный оператор, и я использую его много.

Этот пример немного запутан, потому что характер оператора не ясен из макета и использования.

По крайней мере, мне нравится делать выбор и альтернативы понятными с помощью этого форматирования:

 choice ? true-case : false-case 

Но если мы применим это к вашему коду, это показывает отсутствие ясности в использовании конструкции таким образом:

 return this.Script == null ? false : parameter == "Step" ? true : parameter == "Element" ? this.ElementSelectedInLibrary != null && this.SelectedStep != null : parameter == "Choice" ? this.SelectedElement != null : parameter == "Jump" ? this.SelectedStep != null : parameter == "Conditional jump" ? false : false.Throw("Unknown Add parameter {0} in XAML.".F(parameter)); 

Мне кажется, что мы пытаемся использовать условный оператор, как оператор switch, где оператор switch или, еще лучше, шаблон проектирования, такой как Command Pattern , будет намного яснее.

Мне действительно не нравится этот код. Мне потребовалось более 15 секунд, чтобы понять, поэтому я сдался.

Если бы / было бы предпочтительнее.

Преобразуйте вложенный тройной ключ в переключатель. Никогда не принуждайте одну структуру управления делать плохо или неparsingчиво, что встроенная структура будет делать отлично, особенно если нет очевидной выгоды.

Быть неидиоматичным означает, что вы заставляете читателя тратить время на размышления о том, означает ли то, что они читают, то, что, по их мнению, оно означает.

Поэтому, будучи parsingчивым, он не покупает сложного (а именно, подозрительного) читателя. Это поражает меня как случай умения ради умения.

Есть ли причина не использовать переключатель или else, если построить здесь?

Почему бы не использовать nullool типа bool?

 private bool? CanExecuteAdd(string parameter) { return this.Script == null ? false : parameter == "Step" ? true : parameter == "Element" ? this.ElementSelectedInLibrary != null && this.SelectedStep != null : parameter == "Choice" ? this.SelectedElement != null : parameter == "Jump" ? this.SelectedStep != null : parameter == "Conditional jump" ? false : null; 

}

Сначала я был в ужасе, но на самом деле я не могу придумать способ написать это намного яснее в C # – я пытался подумать о чем-то, где у вас был массив Funcs, сопоставленный с результатами, но он стал еще более уродливым.

Несмотря на то, что parsing фактических условных выражений является грубым, по крайней мере легко понять намерение, хотя я бы предпочел использовать блок переключателей и обрабатывать все остальное как особый случай.

Слишком трудно читать, сначала позаботьтесь об исключениях.

Обращайтесь с каждым случаем в собственном, если, тогда у вас могут быть более сложные условия.

Это один из немногих раз, это много отдельных возвратов в методе будет приемлемым

 private bool CanExecuteAdd(string parameter) { if (this.Script == null) return false; if (parameter.NotIn([] {"Step", "Element", "Choice", "Jump", "Conditional jump"}) throw new Exception("Unknown Add parameter {0} in XAML.".F(parameter)); if (parameter == "Step") return true; if (parameter == "Element") this.ElementSelectedInLibrary != null && this.SelectedStep != null; // etc, etc } 

О, и .NotIn – это метод расширения, противоположный этому, я бы предположил (не могу сказать, что это достаточно точно для того, что необходимо)

 public static bool In(this T obj, IEnumerable arr) { return arr.Contains(obj); } 

Мне все хорошо, но я бы изменил метод Throw:

 static TObject Throw(this TObject ignored, TException exception) { throw exception; } 

Это позволяет указать тип выброса.

К сожалению, тернарный оператор (? 🙂 не является распространенной идиомой на языках C – я встречал много разработчиков C, C ++ и C #, которым приходится делать паузу, чтобы прочитать их, потому что они не знакомы с ним или не используй это. Это не делает его плохой языковой функцией или неparsingчивым, однако те же самые разработчики могут называть пример OP неparsingчивым, потому что он содержит языковые функции, которым им неудобно.

Я не нахожу пример неparsingчивым – я много раз видел вложенных троичных операторов. Тем не менее, я чувствую, что использование переключателя будет предпочтительным выбором для проверки «параметра» на строки.

Для меня гораздо больнее то, что метод расширения Throw игнорирует параметр «this». Что означало бы 42.Throw (…)? Если бы я просмотрел код, я бы назвал его плохим дизайном.

В C & C ++ описанное использование является идиоматическим и причиной для оператора. Преимущество тернарного условного и цепного if-then-else состоит в том, что это выражение с известным типом. В C ++ вы можете написать

 foo_t foo = bar_p ? bar : qux_p ? qux : woz_p ? woz : (throw SomeExpression(), foo_t()) ; 

Обратите внимание на оператор запятой, который возвращает foo_t, который никогда не будет создан из-за броска.

Я на самом деле никогда не видел, чтобы троичный оператор вытолкнул до сих пор. Однако я понял, куда вы направляетесь. Кроме того, я согласен с Джоном, мне не нравится фальшивая часть.