2009-08-16 4 views
73

다음 코드를 상상해보십시오.void 메소드 내에서 return을 사용하는 것은 나쁜 습관입니까?

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

    DoThat(); 
} 

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

void 메서드 내에서 반환을 사용해도됩니까? 성능 저하가 있습니까? 또는 다음과 같은 코드를 작성하는 것이 좋습니다.

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

약 : 무효 DoThis() {if (isValid) DoThat(); } – Dscoduc

+25

코드를 상상해보십시오. 왜? 바로 거기에있다! :-D – STW

+0

이것은 좋은 질문입니다, 저는 항상 좋은 결과를 사용하는 것이 좋다고 생각합니다; 메서드 또는 함수를 종료합니다. 특히 여러 IQueryable 결과가있는 LINQ 데이터 마이닝 메서드에서 모두 서로 의존합니다. 그들 중 하나가 결과가 없다면 경고하고 종료하십시오. – Cheung

답변

2

그러나 코드의 두 번째 조각은 읽기 쉽고 유지하기 때문에 쉽게, 성능 저하가 없습니다.

+0

Russell 나는 당신의 의견에 동의하지 않지만 당신은 그것에 대해 찬성표를 던져서는 안됩니다. +1까지. Btw, 나는 부울 테스트와 빈 줄이 뒤 따르는 한 줄로 돌아 오는 것이 무슨 일이 일어나고 있는지 명확히 보여줄 것이라고 믿는다. 예 : 로드리고의 첫 번째 예. –

+0

나는 이것에 동의하지 않는다. 중첩이 증가해도 가독성이 향상되지는 않습니다. 첫 번째 코드는 완벽하게 이해할 수있는 패턴 인 "guard"문을 사용합니다. – cdmckay

+0

나는 또한 동의하지 않는다. 함수에서 빠져 나가는 보호 절은 일반적으로 독자가 구현을 이해할 수 있도록 도와주는 좋은 방법으로 간주됩니다. –

147

void 메서드의 반환은 나쁘지 않습니다. 보통은 invert if statements to reduce nesting입니다.

그리고 메서드에 중첩을 적게 사용하면 코드 가독성과 유지 관리가 향상됩니다.

사실 return 문이없는 void 메서드가있는 경우 컴파일러는 항상 ret instruction을 끝에 생성합니다.

+13

짧고 달콤하며 정확합니다! 읽을 수있는 주관은 – bdd

2

'성능 저하'는 없지만 대괄호없이 'if'문을 쓰지 마십시오.

항상

if(foo){ 
    return; 
} 

이 방법이 더 읽기입니다; 실수로 코드의 일부가 그렇지 않은 경우에도 해당 진술 내에 있다고 가정 할 수는 없습니다.

+2

입니다. imho, 불필요한 코드에 추가 된 것이 있으면 읽을 수 없게됩니다. (더 읽어야하고, 그 이유가 궁금하고 뭔가를 놓치지 않았는지 궁금합니다) ...하지만 그게 내 것입니다. 주관적인 의견 –

+10

항상 중괄호를 포함하는 더 나은 이유는 가독성과 안전성에 대한 것보다 적습니다. 중괄호가 없으면 나중에 if 구문의 일부로 추가 명령문을 필요로하는 버그를 수정하고,주의를 충분히 기울이지 않고 중괄호를 추가하지 않고 버그를 수정하는 것이 쉽습니다. 중괄호를 항상 포함하면 이러한 위험이 제거됩니다. –

+2

실키,'{'앞에 엔터를 누르십시오. 이렇게하면 동일한 열에'{'를'{'로 묶어서 쉽게 읽을 수 있습니다 (열기/닫기 괄호를 찾기가 훨씬 쉽습니다). – Imagist

17

나쁜 연습 ??? 안돼. 실제로 유효성 검사가 실패하면 가장 빠른 방법으로 반환하여 유효성 검사를 처리하는 것이 항상 좋습니다. 그렇지 않으면 중첩 된 ifelses의 방대한 양이 발생합니다. 초기에 종료하면 코드 가독성이 향상됩니다. 또한

비슷한 질문에 대한 답변 확인 : 두 번째 예는, 더 나은 코드이 경우 Should I use return/continue statement instead of if-else?

1

을하지만 그 무효 함수에서 반환과 아무 상관이 두 번째 코드가 더 있기 때문에, 단순히이다 곧장. 그러나 void 함수에서 반환하는 것은 완전히 좋습니다.

6

(이미 설명한 모든 이유로) 나쁘지 않습니다. 그러나 방법으로 얻는 수익이 많을수록 더 작은 논리적 방법으로 분할해야 할 가능성이 커집니다.

-1

나는이 모든 것의 젊은 whippersnappers에 동의하지 않을 것이다.

무언가 또는 방법의 중간에 반환을 사용하는 것은 아주 나쁜 관행이다. 그것은 거의 40 년 전에 Edsger W. Dijkstra가 잘 알려진 " GOTO 선언문은 유해하다고 간주되며 Dahl, Dijkstra 및 Hoare의 "Structured Programming"에서 계속됩니다.

기본 규칙은 모든 제어 구조와 모든 모듈에 정확히 하나의 항목과 하나의 exit가 있어야한다는 것입니다. 모듈 중간에 명시 적으로 반환하면 해당 규칙이 적용되지 않으므로 프로그램 상태에 대해 추론하기가 훨씬 어려워지며 프로그램이 올바른지 아닌지를 말하기가 훨씬 어려워집니다 (이는 훨씬 더 강력한 속성입니다 "그것이 효과가있는 것처럼 보이는지 아닌지"보다).

"GOTO 성명은 유해한 것으로 간주됩니다"및 "구조화 된 프로그래밍"은 1970 년대의 "구조화 된 프로그래밍"혁명을 시작했습니다.이 두 부분은 오늘날의 if-then-else, while-do 및 다른 명시 적 제어 구조가있는 이유와 고급 언어의 GOTO 문이 멸종 위기에 처한 종 목록에있는 이유입니다. (내 개인 의견으로는 멸종 종 목록에 있어야한다는 것입니다.)

첫 번째 시도에서 수락 테스트를 통과 한 첫 번째 군용 소프트웨어 인 메시지 흐름 변조기는 편차없이 사용하는 것이 중요합니다 , waivers, 또는 "그래,하지만"구어체는 GOTO 문장조차도 사용하지 않는 언어로 작성되었습니다.

Nicklaus Wirth가 Oberon 프로그래밍 언어의 최신 버전 인 Oberon-07에서 RETURN 문의 의미를 변경하여 입력 된 프로 시저 (즉, 함수) 선언의 후미 조각으로 만들었습니다. 함수의 본문에있는 실행 가능 명령문이 아닙니다. 변경에 대한 그의 설명에 따르면 이전 양식 인 WAS이 구조화 프로그래밍의 한쪽 출입 금지 원칙을 위반했기 때문에 정확하게 수행했다고합니다.

+0

예외는 여기에 어떻게 맞습니까? – nairdaen

+1

@ 존 : 우리는 파스칼 (우리 중 대부분, 어쨌든)을 넘을 때 여러 번 반환에 대한 다이크 스트라 금지 명령을 넘겼습니다. –

+0

여러 번의 반품이 필요한 경우는 종종 방법이 너무 많은 노력을 기울여야한다는 신호입니다. 나는 이것까지 John만큼 멀리 가지 않을 것이고, 매개 변수 유효성 검사의 일환으로 반환 진술은 합리적인 예외 일 수 있지만, 그 아이디어가 어디에서 오는지 알 수 있습니다. – kyoryu

4

첫 번째 예는 guard 문을 사용하고 있습니다. Wikipedia에서 :

컴퓨터 프로그래밍에서, 가드는 문제의 지점에 계속 프로그램 실행 인 경우 true로 을 평가해야 부울 식입니다.

나는 방법의 상단에 경비원이 많다고 생각하면 프로그래밍 할 수있는 완벽한 방법이라고 생각합니다. 기본적으로 "이 중 하나라도 사실이라면이 방법을 실행하지 마십시오"라고 말합니다.

그래서 일반적으로는이를 좋아하는 것 :

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

명백히 이것은 단순한 경우이지만, 프로그래머는 제 (중첩 된 코드)의 예는 프로그램에 충돌을 추가했다. 두 번째 예 (가드가있는 조기 종료)에서 가드를 지나치면 코드가 의도하지 않게 null 참조를 사용하는 것이 안전합니다.

물론 위대한 프로그래머는 이와 같은 실수를 저 지르지 않습니다 (종종). 그러나 예방은 치료보다 낫습니다 - 우리는이 잠재적 인 오류 원인을 완전히 제거하는 방식으로 코드를 작성할 수 있습니다. 중첩은 복잡성을 증가 시키므로 중첩을 줄이기 위해 코드 리팩토링을 권장합니다.

+0

그렇습니다. 그러나 다른 한편으로는, 여러 조건의 중첩은 조건에 따라 코드가 버그에 더욱 취약 해지고, 추적하기가 더 어렵고, 더 중요한 것은 디버깅하기가 더 어렵습니다. 평면 기능은 덜 악합니다, IMO. – Skrim

+17

나는 중첩 축소에 대해 논쟁 중입니다! :-) –

+0

나는 이것에 동의한다. 또한 리팩터러 관점에서, obj가 구조체가되거나 보증 할 수있는 무언가가 null이되지 않으면 리팩터링하는 것이 더 쉽고 안전합니다. –

-1

개체가 null 일 때 아무 것도 반환하지 않고 예외를 throw합니다.

귀하의 방법은 객체가 null이 될 것으로 기대하고 예외를 던지고 호출자가 처리하도록해야하므로이 아니다.

그러나 조기 귀국은 다른 경우를 나쁘게 생각하지 않습니다.

관련 문제