이러한 예외를 던지지 않는 이유는 무엇입니까?


111

나는 우연히 이 MSDN 페이지 상태가 :

자체 소스 코드에서 의도적으로 Exception , SystemException , NullReferenceException 또는 IndexOutOfRangeException을 발생 시키지 마십시오 .

불행히도 그 이유를 설명 할 필요가 없습니다. 나는 그 이유를 추측 할 수 있지만 주제에 대해 더 권위있는 누군가가 그들의 통찰력을 제공 할 수 있기를 바랍니다.

처음 두 가지는 분명한 의미가 있지만, 후자의 두 가지는 당신이 고용하고 싶은 것 같습니다 (사실 저는 가지고 있습니다).

또한 이것들이 피해야 할 유일한 예외입니까? 다른 사람이 있다면 무엇이며 왜 피해야합니까?


22
에서 msdn.microsoft.com/en-us/library/ms182338.aspx : 당신이 그런 라이브러리 또는 프레임 워크의 예외 또는 SystemException이 같은 일반적인 예외 유형을 던질 경우, 그것은 그들이 할 수 있음을 알 수없는 예외를 포함하여 모든 예외를 잡기 위해 소비자를 강제로 처리하는 방법을 모릅니다.
Henrik

3
NullReferenceException을 던지는 이유는 무엇입니까?
Rik

5
@Rik : NullArgumentException어떤 사람들은 둘 다 혼동 할 수있는 것과 비슷 합니다.
Moslem Ben Dhaou

2
내 대답에 따라 @Rik 확장 방법
Marc Gravell

3
당신이 던져 안 또 다른 하나는ApplicationException
매튜 왓슨

답변:


98

Exception모든 예외에 대한 기본 유형이므로 매우 구체적이지 않습니다. 유용한 정보가 포함되어 있지 않기 때문에이 예외를 throw해서는 안됩니다. 예외를 포착하는 코드를 호출하는 것은 완전히 원하지 않는 다른 시스템 예외에서 의도적으로 throw 된 예외 (논리에서)를 명확하게 할 수 없으며 실제 오류를 지적 할 수 없습니다.

같은 이유가 SystemException. 파생 된 유형 목록을 보면 매우 다른 의미를 가진 수많은 다른 예외를 볼 수 있습니다.

NullReferenceException그리고 IndexOutOfRangeException다른 종류의 수 있습니다. 이제 이들은 매우 구체적인 예외는, 그래서 그들이 던지는 괜찮을. 그러나 일반적으로 논리에 실제 실수가 있음을 의미하므로 여전히 던지고 싶지 않을 것입니다. 예를 들어 null 참조 예외는 인 개체의 멤버에 액세스하려고 함을 의미합니다 null. 그것이 당신의 코드에서 가능성이 있다면, 당신은 항상 명시 적으로 null더 유용한 예외를 확인 하고 대신 던져야합니다 (예 ArgumentNullException:). 마찬가지로 IndexOutOfRangeExceptions는 목록이 아닌 배열에서 잘못된 인덱스에 액세스 할 때 발생합니다. 항상 처음에는 그렇게하지 않도록하고 배열의 경계를 먼저 확인해야합니다.

몇 가지 다른 예를 들어 두 같은 예외가 있습니다 InvalidCastException또는 DivideByZeroException코드에서 특정 오류에 대한 던져 일반적으로 당신이 뭔가 잘못을하고 또는 당신이 먼저 몇 가지 잘못된 값을 검사하지 않는 것을 의미하고 있습니다. 코드에서 의도적으로 던짐으로써 호출 코드가 코드의 일부 결함으로 인해 던진 것인지 또는 구현에서 무언가를 위해 재사용하기로 결정했기 때문에 발생했는지 확인하기가 더 어려워집니다.

물론 이러한 규칙에는 몇 가지 예외 (하)가 있습니다. 기존의 것과 정확히 일치하는 예외를 유발할 수있는 무언가를 빌드하는 경우, 특히 내장 된 동작과 일치시키려는 경우 자유롭게 사용하십시오. 그런 다음 매우 구체적인 예외 유형을 선택했는지 확인하십시오.

그러나 일반적으로 필요를 충족하는 (특정) 예외를 찾지 않는 한 항상 특정 예상 예외에 대한 고유 한 예외 유형을 만드는 것을 고려해야합니다. 특히 라이브러리 코드를 작성할 때 예외 소스를 분리하는 데 매우 유용 할 수 있습니다.


3
세 번째 부분은 나에게 거의 의미가 없습니다. 물론 이러한 오류가 시작되는 것을 피해야합니다. 예를 들어 IList구현을 작성할 때 요청 된 인덱스에 영향을주는 것은 귀하의 권한이 아닙니다 . 인덱스가 유효하지 않은 경우 호출자의 논리 실수이며이를 알릴 수만 있습니다. 적절한 예외를 발생시켜이 논리 오류를 해결합니다. 왜 IndexOutOfRangeException적절하지 않습니까?

7
@delnan 구현 IList하는 ArgumentOutOfRangeException경우 인터페이스 문서에서 제안 하는 대로 a 를 던질 것 입니다. IndexOutOfRangeException내가 아는 한 배열을 다시 구현할 수 없습니다.
찌를

2
또한 다소 관련이있을 수있는 NullReferenceException것은 일반적으로 내부적으로 AccessViolationException(IIRC 테스트는와 같은 것 cmp [addr], addr입니다. 즉, 포인터를 역 참조하려고 시도하고 액세스 위반으로 실패하면 NRE와 AVE 간의 차이를 처리합니다.) 결과 인터럽트 핸들러에서). 따라서 의미 론적 이유를 제외하고 일부 부정 행위도 포함됩니다. 또한 도움 null이되지 않을 때 수동으로 확인 하지 않도록하는 데 도움이 될 수 있습니다. 어쨌든 NRE를 던지려는 경우 .NET에서 그렇게하지 않는 이유는 무엇입니까?
Luaan 2014 년

마지막 진술과 관련하여 사용자 지정 예외에 대해 :이 작업을 수행 할 필요성을 느낀 적이 없습니다. 아마도 내가 뭔가를 놓치고있는 것 같습니다. 어떤 조건에서 프레임 워크 대신 사용자 지정 예외 유형을 만들어야합니까?
DonBoitnott 2014 년

1
음, 작은 응용 프로그램의 경우 필요하지 않을 수 있습니다. 그러나 개별 부품이 독립적 인 "구성 요소"로 작동하는 더 복잡한 것을 생성하자마자 사용자 지정 오류 상황에 대한 사용자 지정 예외를 도입하는 것이 합리적입니다. 예를 들어 액세스 제어 계층이 있고 권한이 없는데도 일부 서비스를 실행하려고하면 사용자 지정 "액세스 거부 예외"등이 발생할 수 있습니다. 또는 일부 파일을 구문 분석하는 구문 분석기가있는 경우 사용자에게 다시보고 할 자체 구문 분석기 오류가있을 수 있습니다.
찌를

36

마지막 2의 의도는 예상되는 의미를 가진 내장 된 예외와의 혼동을 방지하는 것입니다. 그러나, 나는 그 의견 해요 당신이 예외의 정확한 의도를 보존하는 경우 : 그것은 올바른 하나입니다 throw. 예를 들어 사용자 지정 컬렉션을 작성하는 경우 IndexOutOfRangeExceptionIMO보다 명확하고 구체적인 IMO 를 사용하는 것이 전적으로 합리적으로 보입니다 ArgumentOutOfRangeException. 반면 List<T>후자를 선택할 수있다 적어도 (배열을 포함하지 않음) BCL 41 곳 (반사판의 제공) 맞춤이 던져 IndexOutOfRangeException특별 공제를받을 자격 "낮은 수준"충분히있는 아무 것도 없음은 -. 그래서 네, 그 지침이 어리 석다고 주장 할 수 있다고 생각합니다. 마찬가지로,NullReferenceException 확장 메서드에서 유용합니다-의미 체계를 유지하려는 경우 :

obj.SomeMethod(); // this is actually an extension method

A는 발생 NullReferenceException하는 경우 obj입니다 null.


2
"예외의 정확한 의도를 유지하고 있다면"-확실히 그럴 경우 처음에 테스트 할 필요없이 예외가 throw 될 것입니까? 이미 테스트를했다면 정말 예외가 아니겠습니까?
PugFugly

5
@PugFugly는 확장 메서드 예제를 보는 데 2 ​​초가 걸립니다. 아니요, 테스트 할 필요 없이는 던지지 않습니다. SomeMethod()구성원 액세스를 수행 할 필요가없는 경우 강제로 수행하는 것은 올바르지 않습니다. 마찬가지로 : BCL에서 custom을 생성하는 41 개 장소 IndexOutOfRangeException와 custom을 생성 하는 16 개 장소NullReferenceException
Marc Gravell

16
내가 확장 방법은 여전히 던져해야한다고 주장 ArgumentNullException대신을 NullReferenceException. 확장 메서드의 구문 설탕이 일반 멤버 액세스와 동일한 구문을 허용하더라도 여전히 매우 다르게 작동합니다. 그리고 NRE를 얻는 것은 MyStaticHelpers.SomeMethod(obj)잘못된 것입니다.
찌르기

1
@PugFugly BCL은 기본적으로 .NET의 핵심 요소 인 "기본 클래스 라이브러리"입니다.
찌를

1
@PugFugly : 조건을 선제 적으로 감지하지 못하면 "불편한"시간에 예외가 발생하는 시나리오가 많이 있습니다. 작업이 성공하지 못할 경우 예외를 일찍 발생시키는 것이 작업을 시작하여 중간에 한 다음 부분적으로 처리 된 혼란을 정리하는 것보다 낫습니다.
supercat

5

지적했듯이 예외를 던질 때 피할 일 항목 아래의 예외 만들기 및 던지기 (C # 프로그래밍 가이드) 문서 에서 Microsoft는 실제로 사용자 고유의 소스 코드에서 의도적으로 throw해서는 안되는 예외 유형을 나열 합니다.System.IndexOutOfRangeException

그러나 반대로 기사 throw (C # Reference) 에서 Microsoft는 자체 지침을 위반하는 것으로 보입니다. 다음은 Microsoft가 예제에 포함시킨 방법입니다.

static int GetNumber(int index)
{
    int[] nums = { 300, 600, 900 };
    if (index > nums.Length)
    {
        throw new IndexOutOfRangeException();
    }
    return nums[index];
}

따라서 Microsoft 자체는 IndexOutOfRangeException문서에서 의 던짐을 보여 주므로 일관성이 없습니다 throw.

이것은 적어도의 경우 에는 프로그래머 IndexOutOfRangeException가 예외 유형 던지고 수용 가능한 관행으로 간주 될 수있는 경우가있을 수 있다고 믿게합니다 .


1

내가 질문을 읽을 때, 나는 하나의 예외 유형을 던져 원하는 것이 무엇 조건에서 자신을 요청 NullReferenceException, InvalidCastException또는 ArgumentOutOfRangeException.

제 생각에는 이러한 예외 유형 중 하나가 발생하면 컴파일러가 저에게 말하고 있다는 의미에서 (개발자) 경고가 걱정됩니다. 따라서 개발자 (개발자)가 이러한 예외 유형을 던지도록 허용하는 것은 (컴파일러) 책임을 판매하는 것과 같습니다. 예를 들어, 이것은 컴파일러가 이제 개발자가 객체가 null. 그러나 그러한 결정을 내리는 것은 실제로 컴파일러의 일이어야합니다.

추신 : 2003 년부터는 원하는대로 예외를 처리 할 수 ​​있도록 자체적으로 예외를 개발해 왔습니다. 그렇게하는 것이 가장 좋은 방법이라고 생각합니다.


좋은 점. 그러나 프로그래머가 .NET Framework 런타임이 이러한 유형의 예외를 throw하도록해야하며 프로그래머가이를 적절한 방식으로 처리해야한다고 말하는 것이 더 정확할 것이라고 생각합니다.
DavidRR 2014

0

에 대한 논의를 퍼팅 NullReferenceExceptionIndexOutOfBoundsException따로 :

무엇 잡기와 던지기에 대해 System.Exception. 나는 내 코드에서 이러한 유형의 예외를 많이 던졌고 결코 망쳐지지 않았습니다. 비슷하게, 나는 종종 불특정 Exception유형을 포착하고 나에게도 꽤 잘 작동했습니다. 그렇다면 그 이유는 무엇입니까?

일반적으로 사용자는 오류 원인을 구별 할 수 있어야한다고 주장합니다. 내 경험에 비추어 볼 때 다른 예외 유형을 다르게 처리하려는 상황이 거의 없습니다. 사용자가 프로그래밍 방식으로 오류를 처리 할 것으로 예상되는 경우보다 구체적인 예외 유형을 발생시켜야합니다. 다른 경우에는 일반적인 모범 사례 지침에 확신이 없습니다.

그래서 던지기와 관련 Exception하여 모든 경우에 이것을 금지 할 이유가 없습니다.

편집 : 또한 MSDN 페이지에서 :

일반 실행의 일부로 프로그램의 흐름을 변경하는 데 예외를 사용해서는 안됩니다. 예외는 오류 조건을보고하고 처리하는 데만 사용해야합니다.

다른 예외 유형에 대해 개별 논리로 catch 절을 과도하게 사용하는 것도 모범 사례가 아닙니다.


무슨 일이 일어 났는지 알려주는 예외 메시지가 여전히 존재합니다. 소비자가 프로그래밍 방식으로 이러한 오류를 구별하려는 경우를 대비하여 각 다른 오류에 대해 새로운 예외 유형을 생성하는 것을 상상할 수 없습니다.
uebe

이전 댓글은 어떻게 되었나요?
DonBoitnott
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.