잘못된 제네릭 형식 인수에 대한 최상의 예외


106

현재 열거 형과 관련된 일반적인 메서드가있는 UnconstrainedMelody에 대한 코드를 작성 중 입니다.

이제 "플래그"열거 형 에만 사용되는 메서드가 포함 된 정적 클래스가 있습니다. 나는 이것을 제약 조건으로 추가 할 수 없으므로 다른 열거 형 유형으로도 호출 될 수 있습니다. 이 경우 예외를 던지고 싶지만 어떤 예외를 던질 지 잘 모르겠습니다.

이것을 구체적으로 만들기 위해 다음과 같은 것이 있으면 :

// Returns a value with all bits set by any values
public static T GetBitMask<T>() where T : struct, IEnumConstraint
{
    if (!IsFlags<T>()) // This method doesn't throw
    {
        throw new ???
    }
    // Normal work here
}

던지기에 가장 좋은 예외는 무엇입니까? ArgumentException논리적으로 들리지만 일반적인 인수가 아닌 유형 인수 이므로 쉽게 혼동 될 수 있습니다. 내 TypeArgumentException수업을 소개해야하나요 ? 사용 InvalidOperationException? NotSupportedException? 다른 건 없나요?

나는 것 보다는 그것을 분명히 옳은 일이 아니면이 내 자신의 예외를 만들 수 없습니다.


나는 오늘 제약으로 설명 할 수없는 추가 요구 사항이 사용되는 유형에 배치되는 일반적인 방법을 작성하면서 이것을 우연히 발견했습니다. BCL에서 이미 예외 유형을 찾지 못한 것에 놀랐습니다. 그러나이 정확한 딜레마는 몇 일 전에 동일한 프로젝트에서 Flags 속성으로 만 작동하는 제네릭에 대해 직면 한 것입니다. 유령 같은!
Andras Zoltan

답변:


46

NotSupportedException 분명히 맞는 것처럼 들리지만 문서에는 다른 목적으로 사용해야한다고 분명히 명시되어 있습니다. MSDN 클래스 비고에서 :

기본 클래스에서 지원되지 않는 메서드가 있으며 이러한 메서드는 대신 파생 클래스에서 구현 될 것으로 예상됩니다. 파생 클래스는 기본 클래스에서 메서드의 하위 집합 만 구현하고 지원되지 않는 메서드에 대해서는 NotSupportedException을 throw 할 수 있습니다.

물론 NotSupportedException, 특히 상식적인 의미를 고려할 때 분명히 충분히 좋은 방법이 있습니다. 그렇게 말했지만 그것이 옳은지 잘 모르겠습니다.

Unconstrained Melody 의 목적을 감안할 때 ...

"T : enum"또는 "T : delegate"의 형식 제약 조건이있는 제네릭 메서드 / 클래스로 수행 할 수있는 다양한 유용한 작업이 있지만 불행히도 C #에서는 금지되어 있습니다.

이 유틸리티 라이브러리는 ildasm / ilasm ...

... 그것은 Exception우리가 관습을 만들기 전에 당연히 만나야 만하는 증명의 높은 부담에도 불구하고 새로운 순서가 될 것 같습니다 Exceptions. InvalidTypeParameterException라이브러리 전체에서 다음 과 같은 것이 유용 할 수도 있습니다 (또는 그렇지 않을 수도 있습니다. 이건 확실히 엣지 케이스 죠?).

클라이언트가이를 BCL 예외와 구별 할 수 있어야합니까? 클라이언트가 실수로 바닐라를 사용하여 이것을 언제 호출 할 수 enum있습니까? 사용자 지정 예외 클래스를 작성할 때 고려해야 할 요소는 무엇입니까? 에 대한 허용 된 답변에 의해 제기 된 질문에 어떻게 대답 하시겠습니까?


사실 거의 코드 계약 ... 난 사람이 믿지 않는 않는 것과 같은 방식으로, 처음에 내부 전용 예외를 발생 끌리기 해야 그것을 잡는한다.
Jon Skeet

안타깝게도 null을 반환 할 수 없습니다!
Jeff Sternal

25
TypeArgumentException을 사용하겠습니다.
Jon Skeet

프레임 워크에 예외를 추가하면 "증거 부담"이 높아질 수 있지만 사용자 지정 예외를 정의하면 안됩니다. 상황이 좋아 InvalidOperationException"푸 이미 존재하는 무언가를 추가 수집 줄을 요청, 그래서 바 IOE을 던졌습니다"와 "푸 뭔가를 추가 수집 줄을 요청, 그래서 바도 바 있지만 그것에 기대되지 IOE를 던졌습니다 보즈를 호출"때문에 구역질이 둘 다 동일한 예외 유형을 발생시킵니다. 첫 번째를 잡을 것으로 예상되는 코드는 후자를 기대하지 않습니다. 그 말은 ...
supercat

... 여기서 프레임 워크 예외에 찬성하는 주장은 사용자 지정 예외보다 더 매력적이라고 ​​생각합니다. NSE의 일반적인 특성은 일반적인 유형으로 객체를 참조하고 참조 포인트가 능력을 지원하는 특정 유형의 객체의 전부가 아닌 일부를 참조 할 때 특정 유형에 대한 능력을 사용하려고 시도하는 것입니다. 그것은 NSE를 던져야 지원하지 않습니다. 나는 그들 사이에 "상속"관계가 없더라도 Foo<T>"일반적인 유형"과 Foo<Bar>그 맥락에서 "특정 유형"이라고 생각한다.
supercat 2013 년

24

NotSupportedException을 피할 것입니다. 이 예외는 메서드가 구현되지 않은 프레임 워크에서 사용되며이 유형의 작업이 지원되지 않음을 나타내는 속성이 있습니다. 여기에 맞지 않습니다

InvalidOperationException이 여기서 던질 수있는 가장 적절한 예외라고 생각합니다.


NSE에 대해 알려 주셔서 감사합니다. 겠습니까는 ... BTW, 너무 동료로부터의 입력을 환영합니다
존 소총을

요점은 Jon이 필요로하는 기능이 BCL에서 비슷한 것이 없다는 것입니다. 컴파일러는 그것을 잡아야합니다. NotSupportedException에서 "property"요구 사항을 제거하면 언급 한 것 (예 : ReadOnly 컬렉션)이 Jon의 문제에 가장 가까운 것입니다.
Mehrdad Afshari

한 가지 요점은 IsFlags 메서드 (일반적인 메서드 여야 함)가 있는데 , 이는 이러한 유형의 작업이 지원되지 않는다는 것을 나타내는 일종의 것이므로 NSE가 적절할 것입니다. 즉, 발신자 먼저 확인할 수 있습니다 .
Jon Skeet

@ 존 : 난 당신이 그런 속성이없는 경우에도 생각 하지만, 당신의 유형의 모든 구성원이 본질적으로 사실에 의존 T입니다 enum장식 Flags, NSE를 던질 유효 할 것이다.
Mehrdad Afshari

1
@ 존은 : StupidClrException재미있는 이름을 만든다)
메흐 다드 Afshari에게

13

일반 프로그래밍은 유효하지 않은 유형 매개 변수에 대해 런타임에 발생하지 않아야합니다. 컴파일해서는 안되며 컴파일 시간을 시행해야합니다. 무엇이 IsFlag<T>()포함되어 있는지 모르겠지만 아마도 이것을 '플래그'로만 생성 할 수있는 유형을 생성하려는 것과 같이 컴파일 시간 적용으로 전환 할 수 있습니다. 아마도 traits클래스는 도움이 될 수 있습니다.

최신 정보

당신이 경우 해야한다 던지, 내가 InvalidOperationException이 투표 것입니다. 그 이유는 제네릭 형식에는 매개 변수가 있고 (메서드) 매개 변수 와 관련된 오류는 ArgumentException 계층을 중심으로 이루어지기 때문입니다. 그러나 ArgumentException에 대한 권장 사항 에 따르면

실패가 인수 자체를 포함하지 않는 경우 InvalidOperationException을 사용해야합니다.

메서드 매개 변수 권장 사항이 일반 매개 변수 에도 적용 된다는 믿음이 적어도 한 번 있습니다 . 그러나 SystemException 계층 구조 imho에는 더 나은 것이 없습니다.


1
아니요, 이것이 컴파일 타임에 제한 될 수있는 방법은 없습니다. IsFlag<T>열거 형이 [FlagsAttribute]적용 되었는지, CLR에 특성 기반 제약 조건 이 없는지 여부를 확인합니다 . 그것은 완벽한 세상에서-아니면 그것을 제한하는 다른 방법이있을 것입니다-그러나이 경우에는 작동하지 않습니다 :(
Jon Skeet

(하지만 일반적인 원칙은 +
1-

9

나는 당신이 말하는 것처럼 NotSupportedException을 사용할 것입니다. 특정 열거 형 이외의 다른 열거 형은 지원되지 않습니다 . 물론 이것은 예외 메시지에서 더 명확하게 설명됩니다.


2
NotSupportedException은 BCL에서 매우 다른 목적으로 사용됩니다. 여기에 맞지 않습니다. blogs.msdn.com/jaredpar/archive/2008/12/12/…
JaredPar

8

나는 함께 갈 것이다 NotSupportedException. 하지만 ArgumentException방법에 전달 된 인수가 받아 들일 때 외모 벌금, 그것은 정말 예상됩니다. 형식 인수는 실제 "인수"가 아니라 호출하려는 실제 메서드에 대한 정의 특성입니다. InvalidOperationException수행중인 작업이 일부 경우에 유효 할 수 있지만 특정 상황에서는 허용되지 않을 때 throw되어야합니다.

NotSupportedException작업이 본질적으로 지원되지 않을 때 발생합니다. 예를 들어, 특정 멤버가 클래스에 적합하지 않은 인터페이스를 구현할 때. 이것은 비슷한 상황처럼 보입니다.


음. 아직하지 않는 아주 잘 느끼지만, 나는 그것에 가장 가까운 일이 될 것 같아.
Jon Skeet

Jon : 당연히 컴파일러에 의해 잡힐 것으로 예상하기 때문에 옳지 않은 것 같습니다.
Mehrdad Afshari

예. 이것은 제가 적용하고 싶지만 적용 할 수없는 이상한 종류의 제약입니다. :)
Jon Skeet

6

Microsoft는 예외 섹션 ArgumentExceptionExpression.Lambda <> , Enum.TryParse <> 또는 Marshal.GetDelegateForFunctionPointer <> 예제 에서 설명한 것처럼이를 사용 합니다. ( TDelegate및에 대한 로컬 참조 소스를 검색했지만) 그렇지 않은 경우를 나타내는 예를 찾을 수 없습니다 TEnum.

따라서 최소한 Microsoft 코드에서는 ArgumentException기본 변수 외에 잘못된 제네릭 형식 인수 를 사용하는 것이 일반적인 관행이라고 가정하는 것이 안전하다고 생각합니다 . 문서 의 예외 설명 이 이들을 구별하지 않는다는 점을 감안할 때 너무 무리가 아닙니다.

바라건대 그것은 질문을 단번에 결정합니다.


프레임 워크의 단일 예제로는 충분하지 않습니다. MS가 다른 경우에 잘못된 선택을했다고 생각하는 곳의 수를 감안할 때 :) 단순히 형식 인수가 규칙이 아니기 때문에 TypeArgumentException에서 파생 ArgumentException되지 않습니다. 논의.
Jon Skeet

1
"MS가 일관되게하는 일"이라는 측면에서 확실히 더 매력적입니다. 문서와 일치하는 측면에서 더 이상 매력적이지 않습니다 ... 그리고 C # 팀에는 정규 인수와 형식 인수의 차이에 대해 깊이 관심을 갖는 많은 사람들이 있다는 것을 알고 있습니다. :) 그러나 예제에 감사드립니다- 매우 도움이됩니다.
Jon Skeet

@Jon Skeet : 수정했습니다. 이제 다른 MS 라이브러리의 3 가지 예제가 포함되어 있으며, 모두 ArgumentException이 throw 된 것으로 문서화되었습니다. 그래서 그것이 나쁜 선택이라면 적어도 일관된 나쁜 선택입니다. ;) Microsoft는 일반 인수와 형식 인수가 모두 인수라고 가정합니다. 개인적으로 그런 가정이 상당히 합리적이라고 생각합니다. ^^ '
앨리스

아, 신경 쓰지 마세요. 이미 눈치 채 셨던 것 같습니다. 도와 드릴 수있어서 기쁩니다. ^^
Alice

나는 그들을 똑같이 대하는 것이 합리적인지에 대해 우리가 동의하지 않을 것이라고 생각합니다. 성찰이나 언어 규칙 등에 관해서는 확실히 동일하지 않습니다 . 매우 다르게 처리 됩니다.
Jon Skeet


2

사용자 지정 예외를 throw하는 것은 의심스러운 경우 항상 수행해야합니다. 사용자 지정 예외는 API 사용자 요구에 관계없이 항상 작동합니다. 개발자가 신경 쓰지 않으면 예외 유형을 포착 할 수 있지만 개발자가 특별한 처리가 필요하면 SOL이됩니다.


또한 개발자는 XML 주석에 발생한 모든 예외를 문서화해야합니다.
Eric Schneider

1

NotSupportedException에서 상속하는 것은 어떻습니까? @Mehrdad와 가장 합리적이라는 데 동의하지만 완벽하게 맞지 않는 것 같다는 귀하의 요점을 들었습니다. 따라서 NotSupportedException에서 상속하면 API에 대해 코딩하는 사람들이 여전히 NotSupportedException을 포착 할 수 있습니다.


1

나는 항상 사용자 정의 예외를 작성하는 것을 조심합니다. 순전히 그들이 항상 명확하게 문서화되지 않고 올바르게 이름이 지정되지 않으면 혼란을 야기한다는 근거에 근거합니다.

이 경우 플래그 검사 실패에 대해 ArgumentException을 throw합니다. 그것은 모두 선호도에 달려 있습니다. 내가 본 일부 코딩 표준은 이와 같은 시나리오에서 어떤 유형의 예외를 던져야하는지 정의하는 데까지 이르렀습니다.

사용자가 열거 형이 아닌 것을 전달하려고하면 InvalidOperationException이 발생합니다.

편집하다:

다른 사람들은 이것이 지원되지 않는다는 흥미로운 점을 제기합니다. NotSupportedException에 대한 나의 유일한 관심은 일반적으로 "암흑 물질"이 시스템에 도입되었을 때 발생하는 예외이거나 다른 방식으로 표현하면 "이 방법은이 인터페이스의 시스템에 들어가야하지만 우리는 이겼습니다. 버전 2.4까지 켜지 마세요. "

또한 NotSupportedExceptions가 "이 소프트웨어의 무료 버전을 실행 중입니다.이 기능은 지원되지 않습니다"라는 라이센스 예외로 throw되는 것을 보았습니다.

편집 2 :

또 다른 가능한 것 :

System.ComponentModel.InvalidEnumArgumentException  

열거자인 잘못된 인수를 사용할 때 throw되는 예외입니다.


나는 그것을 열거 형으로 제한 할 것입니다 (약간의 부지런한 부지런한 후)-내가 걱정하는 플래그 일뿐입니다.
Jon Skeet

나는 그 라이센싱 담당자 LicensingExceptionInvalidOperationException.
Mehrdad Afshari

Mehrdad에 동의합니다. 예외는 프레임 워크에 회색이 많이있는 영역 중 하나입니다. 그러나 나는 이것이 많은 언어에서 동일하다고 확신합니다. (내가 vb6의 런타임 오류 13 hehe로 돌아갈 것이라고 말하지 않음)
Peter

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.