.NET에서 유효하지 않거나 예기치 않은 매개 변수에 대해 어떤 예외가 발생합니까?


163

.NET에서 유효하지 않거나 예기치 않은 매개 변수에 대해 어떤 유형의 예외를 발생시켜야합니까? 언제 다른 것을 선택하지 않습니까?

후속 조치 :

한 달에 해당하는 정수를 기대하는 함수가 있고 '42'를 전달한 경우 어떤 예외를 사용합니까? 컬렉션이 아니더라도 "범위를 벗어난"범주에 속합니까?

답변:


249

: 내가 사용하려면 ArgumentException, ArgumentNullException하고 ArgumentOutOfRangeException.

인수 자체에 그다지 초점을 맞추지 않고 전화를 전체적으로 판단하는 다른 옵션도 있습니다.

  • InvalidOperationException– 인수가 정상일 수 있지만 오브젝트의 현재 상태가 아닙니다. 크레딧은 STW (이전 Yoooder)로갑니다. 그의 답변도 투표하십시오 .
  • NotSupportedException– 전달 된 인수는 유효하지만이 구현에서는 지원되지 않습니다. FTP 클라이언트를 상상하고 클라이언트가 지원하지 않는 명령을 전달합니다.

트릭은 왜 메소드를 원래대로 호출 할 수 없는지를 가장 잘 나타내는 예외를 처리하는 것입니다. 이상적으로 무엇이 잘못되었는지, 왜 잘못되었는지, 어떻게 고쳐야하는지에 대한 예외를 구체적으로 설명해야합니다.

오류 메시지가 도움, 문서 또는 기타 리소스를 가리키는 것을 좋아합니다. 예를 들어, Microsoft는 KB 기사 (예 : "Internet Explorer의 웹 페이지를 방문 할 때"작업이 중단되었습니다 "오류 메시지가 표시되는 이유는 무엇입니까?) 와 함께 첫 단계를 밟았습니다." . 오류가 발생하면 오류 메시지의 KB 기사를 가리 킵니다. 그들이 잘하지 못하는 것은 그들이 왜 실패했는지 말해주지 않는다는 것입니다.

의견을 다시 한 번 STW (ex Yoooder)에게 감사드립니다.


후속 조치에 따라 ArgumentOutOfRangeException 입니다. 이 예외에 대한 MSDN의 의견을 살펴보십시오.

ArgumentOutOfRangeException 메소드가 호출되고 메소드에 전달 된 인수 중 하나 이상이 널 참조가 아닌 경우 발생합니다 (Nothing Visual Basic의 경우) 유효한 값을 포함하지 않을 때 발생합니다.

따라서이 경우 값을 전달하지만 범위가 1-12이므로 유효한 값이 아닙니다. 그러나 문서화 방식에 따라 API에서 발생하는 사항이 명확 해집니다. 내가 말할 수도 있지만 ArgumentOutOfRangeException다른 개발자가 말할 수도 있습니다 ArgumentException. 쉽게 행동을 문서화하십시오.


Psst! 나는 당신이 그의 특정한 질문에 정확하게 대답했다는 것에 동의하지만, 방어 코딩과 검증 매개 변수를 반올림하는 데 도움이되는 아래의 대답을 참조하십시오 ;-D
STW

+1이지만 어떤 예외가 발생했는지 그리고 왜 '올바른'것을 선택하는 것보다 더 중요한지를 문서화합니다.
pipTheGeek

@pipTheGeek-나는 그것이 정말로 논쟁의 여지가 있다고 생각합니다. 문서화는 확실히 중요하지만 소비 개발자는 적극적이거나 방어 적이며 실제로 문서를 자세히 읽을 것을 기대합니다. 최종 사용자는 다른 문서가 아닌 다른 문서를 볼 수 있기 때문에 좋은 문서에 대해 친숙하고 설명적인 오류를 선택합니다. 최종 사용자가 전체 문서를 읽는 가난한 프로그래머보다 가난한 프로그래머에게 설명적인 오류를 전달할 가능성이 더 높습니다
STW

4
ArgumentException을 잡으면 ArgumentOutOfRange도 잡습니다.
Steven Evers

방법 FormatException: 인수의 형식이 유효하지 않거나 복합 형식 문자열이 제대로 구성되지 않은 경우에 발생하는 예외입니다.
Anthony

44

Josh의 답변에 투표했습니다 했지만 목록에 하나 더 추가하고 싶습니다.

인수가 유효하지만 개체가 인수를 사용하지 않아야하는 상태 인 경우 System.InvalidOperationException이 발생해야합니다.

MSDN에서 가져온 업데이트 :

InvalidOperationException은 유효하지 않은 인수 이외의 이유로 메소드 호출 실패가 발생한 경우에 사용됩니다.

객체에 PerformAction (enmSomeAction action) 메소드가 있고 유효한 enmSomeActions가 Open 및 Close라고 가정합니다. PerformAction (enmSomeAction.Open)을 연속으로 두 번 호출하면 두 번째 호출에서 InvalidOperationException이 발생합니다 (약자가 유효하지만 제어의 현재 상태가 아니기 때문에).

방어 적으로 프로그래밍하여 이미 옳은 일을하고 있기 때문에 언급 할 또 다른 예외는 ObjectDisposedException입니다. 객체가 IDisposable을 구현하는 경우 항상 폐기 된 상태를 추적하는 클래스 변수가 있어야합니다. 객체가 삭제되고 메소드가 호출되면 ObjectDisposedException을 발생시켜야합니다.

public void SomeMethod()
{
    If (m_Disposed) {
          throw new ObjectDisposedException("Object has been disposed")
     }
    // ... Normal execution code
}

최신 정보: 후속 조치에 대답하기 : 약간 모호한 상황이며 특정 데이터 세트를 나타내는 데 사용되는 일반 (.NET Generics 의미가 아닌) 데이터 유형에 의해 조금 더 복잡해집니다. 열거 형 또는 다른 강력한 형식의 개체가 더 이상적으로 적합 할 수 있지만 항상 해당 제어 기능이있는 것은 아닙니다.

개인적으로 ArgumentOutOfRangeException에 기대어 유효한 값이 1-12임을 나타내는 메시지를 제공합니다. 내 추론은 개월에 대한 모든 정수 표현이 유효하다고 가정하고 개월에 대해 이야기 할 때 1-12 범위의 값을 기대한다는 것입니다. 특정 달 (31 일이있는 달과 같은) 만 유효하다면 Range per-se를 다루지 않을 것이고 유효한 값을 나타내는 일반적인 ArgumentException을 throw하고 메소드의 주석에 문서화 할 것입니다.


1
좋은 지적. 이것은 유효하지 않은 입력과 그렇지 않은 입력의 차이점을 설명 할 수 있습니다. +1
Daniel Brückner

Psst, 나는 당신이 천둥을 훔치지 않을 것에 동의합니다. 당신이 그것을 지적하기 때문에, 나는 내 대답 업데이트
JoshBerke

38

실제 값과 어떤 예외가 가장 적합한 지에 따라

이것이 정확하지 않은 경우에서 자신의 예외 클래스를 파생하십시오 ArgumentException.

요우 더의 대답이 저를 깨달았습니다. 입력은 유효하지 않은 입력이있는 동안은 언제든지 유효하지 않은 경우 예상치 못한 이 시스템의 현재 상태에 대해 유효하지 않은 경우. 따라서 나중에 InvalidOperationException는 합리적인 선택입니다.


6
InvalidOperationException의 MSDN 페이지에서 발췌 : "InvalidOperationException은 유효하지 않은 인수 이외의 이유로 메소드 호출 실패가 발생한 경우에 사용됩니다."
STW


3

ArgumentException :

ArgumentException은 메소드가 호출되고 전달 된 인수 중 하나 이상이 호출 된 메소드의 매개 변수 스펙을 충족하지 않는 경우 발생합니다. ArgumentException의 모든 인스턴스에는 유효하지 않은 인수와 인수의 예상 값 범위를 설명하는 의미있는 오류 메시지가 포함되어야합니다.

특정 유형의 무효성에 대해 몇 개의 서브 클래스도 존재합니다. 링크에는 하위 유형과 적용시기가 요약되어 있습니다.


1

짧은 대답 :
둘 다

더 긴 대답 :
Argument * 예외 사용 (구성 요소 라이브러리와 같이 제품이있는 라이브러리 제외)은 냄새입니다. 예외는 버그가 아닌 예외적 인 상황을 처리하고 사용자 (즉, API 소비자) 부족이 아닌 경우를 처리하는 것입니다.

가장 긴 대답 :
라이브러리를 작성하지 않으면 유효하지 않은 인수에 대한 예외를 던지는 것은 무례합니다.
나는 두 가지 이상의 이유로 단언을 사용하는 것을 선호한다.

  • 어설 션은 테스트 할 필요가 없으며 던지기 어설 션은 수행 할 수 있으며 ArgumentNullException에 대한 테스트는 어리석은 것처럼 보입니다 (시도하십시오).
  • 어설 션은 장치의 의도 된 용도를보다 잘 전달하며 클래스 동작 사양보다 실행 가능한 문서에 더 가깝습니다.
  • 어설 션 위반 동작을 변경할 수 있습니다. 예를 들어 디버그 컴파일에서 메시지 상자는 괜찮습니다. 따라서 QA가 메시지를 즉시 받아 낼 수 있습니다 (IDE가 발생하는 라인에서 끊어짐) 단위 테스트에서는 어설 션 실패를 테스트 실패로 나타낼 수 있습니다 .

null 예외 처리는 다음과 같습니다 (확실히 냉소적 임).

try {
    library.Method(null);
}
catch (ArgumentNullException e) {
    // retry with real argument this time
    library.Method(realArgument);
}

상황이 예상되지만 예외적 인 경우 (예 : IO 실패와 같이 소비자가 통제 할 수없는 경우) 예외를 사용해야합니다. 인수 * 예외는 버그를 나타내며 테스트로 처리하고 디버그를 지원해야합니다.

BTW :이 경우 int 대신 Month 유형을 사용했을 수 있습니다. 타입 안전 (Aspect # rulez!)에 관해서는 C #이 부족하지만 때로는 이러한 버그를 모두 방지하거나 컴파일 할 수 있습니다.

그리고 네, MicroSoft는 그것에 대해 틀 렸습니다.


6
IMHO, 호출 된 메소드가 합리적으로 진행될 수 없을 때 예외도 발생해야합니다. 여기에는 발신자가 가짜 인수를 통과 한 경우가 포함됩니다. 대신 무엇을 하시겠습니까? -1을 반환 하시겠습니까?
John Saunders

1
잘못된 인수로 인해 내부 함수가 실패하는 경우 내부 함수에서 InvalidArgumentException을 포착하여 더 유용한 정보로 래핑하는 것보다 유효성에 대한 인수 테스트의 장단점이 무엇입니까? 후자의 접근법은 일반적인 경우 성능을 향상시키는 것처럼 보이지만 많이 수행하지는 못했습니다.
supercat

이 질문에 대한 빠른 Google 검색은 일반적인 예외를 던지는 것이 모두의 최악의 관행임을 나타냅니다. 주장에 대한 주장과 관련하여 소규모 개인 프로젝트에서는 이점이 있지만 응용 프로그램에 대한 잘못된 구성 또는 이해 부족으로 인해 잘못된 주장이있을 가능성이 큰 엔터프라이즈 응용 프로그램에서는 그렇지 않습니다.
Max

0

사용할 수있는 표준 ArgumentException이 있거나 서브 클래스 화하여 직접 만들 수 있습니다. 몇 가지 특정 ArgumentException 클래스가 있습니다.

http://msdn.microsoft.com/en-us/library/system.argumentexception(VS.71).aspx

어느 것이 가장 효과가 좋은지.


1
나는 거의 모든 경우에 동의하지 않습니다. 제공된 .NET Argument * Exception 클래스는 매우 일반적으로 사용되며 소비자에게 문제를 알리기에 충분한 특정 정보를 제공 할 수있는 기능을 제공합니다.
STW

명확히하기 위해-Argument * Exception 클래스에서 파생되는 거의 모든 경우에 동의하지 않습니다. .NET Argument Exceptions 중 하나와 설명적이고 명확한 메시지 중 하나를 사용하면 인수가 유효하지 않은 모든 상황에 대해 충분한 세부 정보가 제공됩니다.
STW

동의했지만 방금 사용 가능한 옵션을 설명하고있었습니다. "바람직한"방법에 대해 더 분명해야했습니다.
Scott M.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.