Подтвердить что ты не робот

Неправильная ли практика использования возврата внутри метода void?

Представьте следующий код:

void DoThis()
{
    if (!isValid) return;

    DoThat();
}

void DoThat() {
    Console.WriteLine("DoThat()");
}

Можно ли использовать возврат внутри метода void? Имеет ли какое-либо наказание за производительность? Или было бы лучше написать такой код:

void DoThis()
{
    if (isValid)
    {
        DoThat();
    }
}
4b9b3361

Ответ 1

Возврат в методе void не является плохим, является обычной практикой для инвертировать if для уменьшения вложенности.

И меньше вложенности в ваши методы улучшает читаемость кода и удобство обслуживания.

На самом деле, если у вас есть метод void без какого-либо оператора return, компилятор всегда будет генерировать инструкцию ret в конце.

Ответ 2

Есть еще одна серьезная причина для использования охранников (в отличие от вложенного кода): если другой программист добавляет код в вашу функцию, они работают в более безопасной среде.

Рассмотрим:

void MyFunc(object obj)
{
    if (obj != null)
    {
        obj.DoSomething();
    }
}

против

void MyFunc(object obj)
{
    if (obj == null)
        return;

    obj.DoSomething();
}

Теперь представьте, что другой программист добавляет строку: obj.DoSomethingElse();

void MyFunc(object obj)
{
    if (obj != null)
    {
        obj.DoSomething();
    }

    obj.DoSomethingElse();
}

void MyFunc(object obj)
{
    if (obj == null)
        return;

    obj.DoSomething();
    obj.DoSomethingElse();
}

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

Конечно, великий программист не ошибается (часто). Но профилактика лучше, чем лечение - мы можем написать код таким образом, чтобы полностью исключить этот потенциальный источник ошибок. Вложенность добавляет сложности, поэтому лучшие практики рекомендуют рефакторинг кода для уменьшения вложенности.

Ответ 3

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

Также проверьте ответы по аналогичному вопросу: Должен ли я использовать оператор return/continue вместо if-else?

Ответ 4

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

Ответ 5

В первом примере используется инструкция охраны. Из Wikipedia:

В компьютерном программировании охранник является логическое выражение, которое должно оценивать на true, если выполнение программы продолжить в рассматриваемой отрасли.

Я думаю, что наличие кучки охранников наверху метода - это совершенно понятный способ программирования. В основном это говорит: "Не выполняйте этот метод, если какое-либо из них истинно".

В общем, он хотел бы это сделать:

void DoThis()
{
  if (guard1) return;
  if (guard2) return;
  ...
  if (guardN) return;

  DoThat();
}

Я думаю, что гораздо более читабельны:

void DoThis()
{
  if (guard1 && guard2 && guard3)
  {
    DoThat();
  }
}

Ответ 6

Нет никакого штрафа за производительность, однако вторая часть кода более читаема и, следовательно, легче поддерживать.

Ответ 7

Совершенно нормально и нет "штрафа за производительность", но никогда не записывать оператор "if" без скобок.

Всегда

if( foo ){
    return;
}

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

Ответ 8

В этом случае ваш второй пример - лучший код, но это не имеет никакого отношения к возврату из функции void, это просто потому, что второй код более прямой. Но возврат из функции void полностью прекрасен.

Ответ 9

Я собираюсь не согласиться со всеми твоими молодыми стрелками на этом.

Использование возврата в середине метода, void или иначе, является очень плохой практикой, по причинам, которые были четко сформулированы, почти сорок лет назад, покойным Эдсером У. Дейкстре, начиная с известного "GOTO Заявление считается вредным", и продолжает "Структурированное программирование" , Дал, Дейкстра и Хоар.

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

"Заявление GOTO считается вредным" и "Структурированное программирование" началось с революции "Структурированное программирование" 1970-х годов. Эти две части являются причинами, которые мы имеем, если-then-else, while-do и другими явными конструкциями управления сегодня, и почему заявления GOTO на языках высокого уровня находятся в списке находящихся под угрозой исчезновения видов. (Мое личное мнение состоит в том, что они должны быть в списке "Вымершие виды".)

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

Также стоит отметить, что Nicklaus Wirth изменил семантику оператора RETURN в Oberon-07, последней версии языка программирования Oberon, сделав его завершающим фрагментом объявления типизированной процедуры (то есть функции), а не исполняемый оператор в теле функции. Его экспликация об изменении говорит о том, что он сделал это именно потому, что предыдущая форма была нарушением принципа единственного выхода Структурированного программирования.

Ответ 10

Выбросить исключение вместо того, чтобы ничего не возвращать, когда объект имеет значение null и т.д.

Ваш метод ожидает, что объект будет не нулевым, и это не так, поэтому вы должны генерировать исключение и позволить вызывающему агенту обрабатывать это.

Но раннее возвращение - это не плохая практика.