언제 그리고 왜 void를 사용해야합니까 (예 : bool / int 대신)


30

때로는 개발자가 함수에 중요하지 않은 것을 반환하기로 선택한 메서드가 실행됩니다. 내 말은, 코드를 볼 때, 그것은 void생각하는 순간 만큼이나 훌륭하게 작동한다는 것을 의미합니다. "왜?" 익숙한가요?

때때로 나는 같은 것을 반환하는 것이 좋습니다 대부분의 경우 그 동의 bool또는 int보다는 단지를 수행합니다 void. 그러나 큰 그림에서 장단점에 대해서는 확실하지 않습니다.

상황에 따라를 반환 int하면 호출자에게 메서드의 영향을받는 행 또는 개체의 양을 알 수 있습니다 (예 : MSSQL에 저장된 5 개의 레코드). "InsertSomething"과 같은 메소드가 부울을 리턴 true하면 성공하면 else 를 리턴하도록 설계된 메소드를 가질 수 있습니다 false. 발신자는 해당 정보에 따라 행동할지 여부를 선택할 수 있습니다.

반면에

  • 메소드 호출의 덜 명확한 목적으로 이어질 수 있습니까? 잘못된 코딩은 종종 메서드 내용을 다시 확인하도록합니다. 무언가를 반환하면 메서드가 반환 된 결과로 무언가를 수행 해야하는 유형이라는 것을 알려줍니다 .
  • 또 다른 문제는 메소드 구현을 알 수없는 경우 개발자가 중요한 기능이 아닌 것을 반환하기로 결정한 것입니다. 물론 댓글을 달 수 있습니다.
  • 메소드의 닫는 대괄호에서 처리를 종료 할 수있을 때 리턴 값을 처리해야합니다.
  • 후드는 어떻게 되나요? false오류가 발생 하여 호출 된 메소드가 발생 했습니까 ? 아니면 평가 결과로 인해 거짓을 반환 했습니까?

이것에 대한 당신의 경험은 무엇입니까? 이것에 대해 어떻게 행동하겠습니까?


1
void를 반환하는 함수는 기술적으로 전혀 함수가 아닙니다. 방법 / 절차 일뿐입니다. 반환 void메서드의 반환 값은 하찮은 것을 개발자의 노하우는 적어도 수 있습니다; 그것은 가치를 계산하는 것이 아니라 행동을합니다.
KChaloux

답변:


32

메서드의 성공 또는 실패를 나타내는 부울 반환 값의 경우 Try다양한 .NET 메서드에 사용되는 -prefix 패러다임을 선호합니다 .

예를 들어 void InsertRow(), 동일한 키를 가진 행이 이미 존재하는 경우 메소드에서 예외가 발생할 수 있습니다. 문제는 호출자가 InsertRow를 호출하기 전에 행이 고유하다는 것을 가정하는 것이 합리적입니까? 대답이 아니오 bool TryInsertRow()이면 행이 이미 존재하는 경우 false를 반환 하는 을 제공 합니다. db 연결 오류와 같은 다른 경우에도 TryInsertRow는 db 연결 유지가 호출자의 책임이라고 가정 할 때 예외를 throw 할 수 있습니다.


4
예상되는 실패 와 예기치 않은 실패를 처리하는 것에 대한 +1- 내 대답은 이것을 충분히 강조하지 못했습니다.
Péter Török

try 방법과 기본 방법을 유지 관리하기 쉽고 목적을 이해하기 쉽게하는 TryXX 방법의 원리를 발명하려고 시도한 것은 +1입니다.
독립

+1 잘 말했다. 이 질문에 대한 가장 좋은 대답의 핵심은 때때로 호출자에게 예외를 던지는 독단적 인 방법의 옵션을 제공하고자한다는 것입니다. 그러나 이러한 경우 단정적 인 방법으로 예외를 포착하고 위조 처리해서는 안됩니다. 요점은 발신자가 책임을진다는 것입니다. 반면, Try-paradigm (또는 Monad)은 예외를 잡아서 처리 한 다음 세부 정보가 필요한 경우 bool 또는 설명 Enum을 다시 전달해야합니다. 발신자는 Try / Monad가 절대 예외를 발생시키지 않을 것으로 예상합니다. 진입 점과 같습니다.
Suamere

따라서 Try / Monad에서는 예외가 발생하지 않을 것으로 예상되지만 부울은 호출자에게 db 연결이 실패했음을 알리거나 http 요청에 다르게 작동하는 데 필요한 많은 반환 값 중 하나를 알려주기에는 충분하지 않습니다. Try / Monad에는 bool 대신 Enum을 사용할 수 있습니다.
Suamere

TryInsertRow가있는 경우-bool을 반환하는 경우-데이터베이스에 하나 이상의 고유 제약 조건이있는 경우-오류가 무엇인지 정확하게 알고 어떻게 사용자에게 전달합니까? 오류 메시지 / 코드 및 성공 부울이 포함 된 더 풍부한 반환 유형을 사용해야합니까?
niico

28

"상태 코드"를 반환하는 IMHO는 C #과 같은 중상급 언어에서 예외가 일반화되기 전에 역사적 시대에서 비롯된 것입니다. 요즘 예기치 않은 오류로 인해 메소드가 성공하지 못하면 예외를 처리하는 것이 좋습니다. 이렇게하면 오류가 눈에 띄지 않게되며 발신자가 적절하게 처리 할 수 ​​있습니다. 따라서 이러한 경우 메서드가 void부울 상태 플래그 또는 정수 상태 코드 대신 아무것도 반환하지 않는 것이 좋습니다 (예 :). (물론 메소드가 언제 어떤 예외를 던질 수 있는지 문서화해야합니다.)

반면에 엄격한 의미의 함수, 즉 입력 매개 변수를 기반으로 계산을 수행하고 해당 계산 결과를 반환해야하는 경우 반환 유형이 분명합니다.

하나는 둘 사이의 회색 영역이 있습니다 그것의 호출자에 유용하다고 판단되는 경우,이 방법에서 약간의 "추가"정보를 반환하기로 결정가. 삽입에서 영향을받는 행 수에 대한 예와 같습니다. 또는 요소를 연관 콜렉션에 넣는 메소드의 경우 해당 키와 연관된 이전 값이있는 경우이를 리턴하는 것이 유용 할 수 있습니다. 이러한 용도는 API의 (알려지고 예상되는) 사용 시나리오를 신중하게 분석하여 식별 할 수 있습니다.


4
상태 코드에 대한 예외는 +1입니다. 이것에 대한 예외 (나쁜 말장난)는 잘 사용 된 TryXX 패턴입니다.
Andy Lowry

나는 거기에 당신과 함께 있습니다. TcF는 오류를 침묵시키지 않습니다! 아마도 회색 영역 일 것입니다. 항상 뭔가를 돌려주는 것이 있을 있습니다. 영향을받는 행, 최근에 삽입 된 ID, 소프트웨어 실행의 PID이지만 여전히 개발할 때 "지옥, 이걸 반환합니다"라고 생각하는 것이 더 쉽다고 생각합니다. 그런 다음 1 년 후, "무엇입니까? ´int someThing = RunProcess (x) '를 실행할 수 없으면 어떻게됩니까?"
독립

+1 추가 정보는 C #과 같은 고급 언어로 이와 같은 메소드를 코딩하는 이유입니다. 따라서 필요할 때 추가 정보를 쉽게 사용할 수 있습니다.
ashes999

2
-1 와우, 당신의 말은 너무 모순되고 틀 렸습니다. 제어 흐름이나 통신에 예외를 사용해서는 안됩니다. 조건부보다 훨씬 비쌉니다. "예외가 평범 해지기 전에"는 언제입니까? ... try / catch 블록이 평범 해지기 전에 의미합니까? 그 이후로 예외는 흔한 일이었습니다. "예기치 않은 오류가 발생하면 예외를 던지십시오 ..."예상치 못한 일에 대해 어떻게 조치합니까? 왜 예외를 잡아서 다시 던지겠습니까? 너무 비싸요. 왜 "오류"라고 말합니까? 오류와 예외는 다릅니다.
Suamere

1
누가 던져진 예외가 눈에 띄지 않을 것이라고 말합니까? 아무도 catch 블록에 로그인하도록 강요하지 않습니다. 왜 "then"블록에 로그인하지 않습니까? 왜 "어떻게 예외가 발생할 수있는 예외를 문서화"합니까? 자체 문서화 코드를 작성하고 메소드가 해당 메소드의 예상 종료 상태를 가진 열거 형을 단순히 반환하면 어떨까요? 상태를 점검하여 가능한 예외를 피할 수있는 경우 예외없이 잡아서 처리해야합니다.
Suamere

14

피터의 대답은 예외를 잘 다루고 있습니다. 다른 고려 사항은 명령 쿼리 분리와 관련이 있습니다.

CQS 원칙에 따르면 메소드는 명령이거나 둘 다가 아니라 쿼리 여야합니다. 명령은 절대 값을 반환해서는 안되며 상태 만 수정해야하며 쿼리는 상태 만 반환하고 수정해서는 안됩니다. 이것은 의미를 매우 명확하게 유지하고 코드를 더 읽기 쉽고 유지 보수하기 쉽게합니다.

CQS 원칙을 위반하는 경우가 몇 가지 있습니다. 이들은 일반적으로 성능 또는 스레드 안전에 관한 것입니다.


1
-1 잘못과 잘못. 첫째, CQS의 요점은 Q에 있습니다. 호출자는 해당 서비스 상태를 변경하지 않고 일부 상태 저장 서비스를 통해 계산 또는 외부 전화를받을 수 있어야합니다. 또한 CQS는 느슨하게 따르는 데 도움이되는 원칙이지만 특정 디자인에서는 엄격하게 준수해야합니다. 마지막으로 엄격한 CQS에서도 명령이 값을 반환 할 수 없다고 말하지 않으며 외부 계산을 계산하거나 호출하거나 데이터를 반환해서는 안됩니다 . C 또는 Q는 호출자에게 유용한 경우 종료 상태를 자유롭게 반환 할 수 있습니다.
Suamere

아 그러나 명령의 영향을받는 행 수는 이전 명령의 새 명령 작성을 훨씬 쉽게 만듭니다. 출처 : 수년간의 경험.
Joshua

@Joshua : 마찬가지로, "새 레코드를 추가하고 추가 중에 생성 된 ID (일부 구조의 경우 행 번호)를 반환"는 다른 방법으로는 효율적으로 달성 할 수없는 목적으로 사용될 수 있습니다.
supercat

영향을받은 행을 반환하지 않아도됩니다. 명령은 영향을받는 사람의 수를 알아야합니다. # 이외의 것이면 이상한 일이 발생했기 때문에 롤백하고 예외를 던져야합니다. 따라서, 이것은 발신자가 실제로 신경 쓰지 않는 정보입니다 (사용자가 진정한 #를 알아야하고 주어진 데이터에서 알 수 없다면). DB 생성 Id, 스택 / 큐와 같은 회색 영역이 여전히 데이터를 가져와 상태를 변경하는 경우가 있지만 이러한 시나리오에서 "CommandQuery"를 생성하는 것을 좋아하므로 아무도 "이상한"것을 시도하지 않습니다.
Daniel Lorenz

3

경로가 무엇이든간에 이것으로 걸을 것입니다. 나중에 사용할 수 있도록 반환 값이 없어야합니다 (예 : 함수가 항상 true를 반환 함). 리턴 값이있는 경우 항상 사용해야하며이를 사용하려면 최소한 2 개의 리턴 값이 있어야합니다.


+1이 질문에 대한 답은 아니지만 정확한 정보입니다. 결정을 내릴 때 필요에 따라 결정해야합니다. 발신자가 리턴 데이터를 유용하게 찾지 못하면 수행하지 않아야합니다. 그리고 "미래 교정"을 위해 시간의 100 %를 돌려주는 데 아무도 사용하지 않습니다. 만약 "미래"가 며칠 후와 같고 그에 대한 과제가 있다면 그것은 다른 이야기입니다. lol.
Suamere

1

나는 많은 void 함수를 작성했습니다. 그러나 전체 메소드 체인 균열을 겪었으므로 공허가 아닌 이것을 반환하기 시작했습니다. 누군가가 공허로 쪼그리고 앉을 수없는 귀환 원인을 활용할 수도 있습니다. 그리고 그들이 그것으로 아무것도하고 싶지 않다면 무시할 수 있습니다.


1
메소드 체인은 상속을 번거롭고 어렵게 만들 수 있습니다. 메소드에 "void"를 부여하고 싶지 않은 것 외에 다른 이유가 없다면 메소드 체인을 수행하지 않습니다.
KallDrexx

참된. 그러나 상속은 번거롭고 사용하기 어려울 수 있습니다.
Wyatt Barnett

(전체 객체를 언급 한) 무엇이든 반환하는 알려지지 않은 코드를 살펴보면 내부 및 외부 메서드의 흐름을 확인하기 만하면됩니다.
Independent

나는 당신이 Ruby어느 시점에 들어갔다고 생각하지 않습니까? 그것이 메소드 체인을 소개하는 이유입니다.
KChaloux

메서드 체인과 관련된 한 가지 질문은 같은 문장 이 원본에 대한 참조를 return Thing.Change1().Change2();변경 Thing하고 반환 할 것으로 기대 하는지 또는 원본과 다른 새로운 것에 대한 참조를 반환 할 것인지 덜 명확하게한다는 것입니다. 원래 그대로.
supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.