Четкий или нет: C# несколько тернарных операторов + Бросок, если несопоставленный [закрытый]

34
задан Mechanical snail 24 September 2012 в 21:32
поделиться

14 ответов

Я довольно часто использовал такой код в 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;

РЕДАКТИРОВАТЬ: На самом деле, в этом случае я бы не стал использовать if / else или this шаблон ... Я бы использовал переключатель / футляр. Это может быть очень компактным, если вы хотите:

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);
}
27
ответ дан 27 November 2019 в 16:10
поделиться

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

0
ответ дан 27 November 2019 в 16:10
поделиться

Мне кажется, это нормально, но я бы изменил ваш Throw method to:

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

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

1
ответ дан 27 November 2019 в 16:10
поделиться

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

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

2
ответ дан 27 November 2019 в 16:10
поделиться

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

3
ответ дан 27 November 2019 в 16:10
поделиться

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

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

4
ответ дан 27 November 2019 в 16:10
поделиться

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

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

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

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 , был бы намного понятнее.

6
ответ дан 27 November 2019 в 16:10
поделиться

Я голосую за неразборчиво.

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

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

8
ответ дан 27 November 2019 в 16:10
поделиться

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

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

10
ответ дан 27 November 2019 в 16:10
поделиться

Почему бы не использовать тип bool, допускающий значение NULL?

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;

}

2
ответ дан 27 November 2019 в 16:10
поделиться

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

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

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

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<T>(this T obj, IEnumerable<T> arr)
{
    return arr.Contains(obj);
}
1
ответ дан 27 November 2019 в 16:10
поделиться

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

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));
    }
}
29
ответ дан 27 November 2019 в 16:10
поделиться

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

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

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

2
ответ дан 27 November 2019 в 16:10
поделиться

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

Я не считаю этот пример неразборчивым - я много раз видел вложенные тернарные операторы. Однако я считаю, что использование переключателя было бы предпочтительным выбором для проверки «параметра» по строкам.

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

1
ответ дан 27 November 2019 в 16:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: