2009-08-16 6 views
73

Представьте себе следующий код:Неправильная практика использования возврата внутри метода void?

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

    DoThat(); 
} 

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

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

void DoThis() 
{ 
    if (isValid) 
    { 
     DoThat(); 
    } 
} 
+1

О нас: void DoThis() {if (isValid) DoThat(); } – Dscoduc

+25

Представьте себе код? Зачем? Это прямо сейчас! :-D – STW

+0

Это хороший вопрос, я всегда думаю, что это хорошая практика использования возврата; для выхода из метода или функции. Особенно в методе интеллектуального анализа данных LINQ, имеющем несколько результатов IQueryable , и все они зависят друг от друга. Если один из них не имеет результата, оповещения и выхода. – Cheung

ответ

2

Там нет потери производительности, однако вторая часть кода более читабельным и, следовательно, проще в обслуживании.

+0

Russell я не согласен с вашим мнением, но вы не должны были проголосовать за него. +1, чтобы даже это было. Кстати, я считаю, что логический тест и возврат по одной строке, за которой следует пустая строка, - это четкое указание на то, что происходит. например Первый пример Родриго. –

+0

Я не согласен с этим. Увеличение вложенности не улучшает читаемость. Первая часть кода использует оператор «guard», который является совершенно понятным шаблоном. – cdmckay

+0

Я тоже не согласен. Оговорки о защите, которые возникают из ранних функций, как правило, считаются хорошей вещью в наши дни, помогая читателю понять реализацию. –

147

Возврат в виде пустоты не является плохим, распространенной практикой является invert if statements to reduce nesting.

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

Фактически, если у вас есть метод void без оператора возврата, компилятор всегда будет генерировать ret instruction в конце его.

+13

Короткие, сладкие и правильные! – bdd

2

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

Всегда

if(foo){ 
    return; 
} 

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

+2

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

+10

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

+2

Шелковистый, пожалуйста, нажмите enter перед вашим '{'. Это выравнивает ваш '{' с вашим '}' в том же столбце, что значительно облегчает читаемость (гораздо проще найти соответствующие открытые/закрывающие фигурные скобки). – Imagist

17

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

Также проверьте ответы на аналогичный вопрос: Should I use return/continue statement instead of if-else?

1

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

6

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

-1

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

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

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

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

Стоит отметить, что модулятор потока сообщений, первая часть военного программного обеспечения, КОГДА КАЖДОЕ прошло приемное тестирование с первой попытки, без отклонений , отказ, или «да, но» словосочетание, было написано на языке, на котором даже не было заявления GOTO.

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

+0

Как здесь Исключения? – nairdaen

+1

@John: мы получили над Дыкстром запрет на несколько возвратов примерно в то время, когда мы получили над Паскалем (большинство из нас, во всяком случае). –

+0

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

4

Первый пример - инструкция охраны. Из Wikipedia:

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

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

Так что в целом он хотел бы это:

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

    DoThat(); 
} 

Я думаю, что это намного более удобным для чтения, то:

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

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

Рассмотрим:

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(); 
} 

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

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

+0

Да, но с другой стороны, несколько слоев гнездования с их условиями делают код еще более подверженным ошибкам, логику сложнее отслеживать и - что более важно - сложнее отлаживать. Плоские функции - меньшее зло, ИМО. – Skrim

+17

Я спорю в * пользу * от сокращенного гнездования! :-) –

+0

Я согласен с этим. Кроме того, с точки зрения рефакторинга проще и безопаснее реорганизовать метод, если obj становится структурой или что-то, что вы можете гарантировать, не будет равным нулю. –

-1

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

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

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

Смежные вопросы