"특별 수업"이란 정확히 무엇입니까?


114

다음과 같은 내용을 컴파일하지 못한 후 :

public class Gen<T> where T : System.Array
{
}

오류와 함께

제약 조건은 특수 클래스`System.Array '일 수 없습니다.

"특별 수업" 정확히 무엇인지 궁금해졌습니다 .

사람들 System.Enum은 일반적인 제약 조건에서 지정할 때 종종 같은 종류의 오류가 발생하는 것처럼 보입니다 . 나는과 같은 결과를 얻었다 System.Object, System.Delegate, System.MulticastDelegateSystem.ValueType도합니다.

그들 중 더 있습니까? C #에서 "특수 클래스"에 대한 정보를 찾을 수 없습니다.

또한, 무엇 이며 우리가 제네릭 형식 제약 조건으로 사용할 수없는 그 클래스에 대한 특별?


14
나는 이것이 직접적인 복제라고 생각하지 않습니다. 질문은 "왜 이것을 제약으로 사용할 수 없는지"가 아니라 "이 특수 클래스는 무엇인가"입니다. 나는 그 질문들을 살펴 보았고 그들은 "특수 클래스"가 실제로 무엇이고 왜 특별하다고 간주되는지를 설명하지 않고 제약으로 사용하는 것이 왜 쓸모 없는지 설명합니다.
Adam Houldsworth 2015

2
내 경험상 사용되지만 직접 사용할 수없고 다른 구문을 통해서만 암시 적으로 만 사용할 수있는 클래스는 특수 클래스입니다. Enum은 같은 범주에 속합니다. 정확히 무엇이 그들을 특별하게 만드는지 모르겠습니다.
Lasse V. Karlsen 2015

@AndyKorneyev : 그 질문은 좀 다릅니다. 나는 "특수 클래스"의 정의 및 / 또는 이들의 포괄적 인 목록을 요청하고 있습니다. 이 질문은 단순히 System.Array가 제네릭 형식 제약 조건이 될 수없는 이유를 묻습니다.
Mints97 2015

문서 에서 "[...] 시스템과 컴파일러 만 Array 클래스에서 명시 적으로 파생 될 수 있습니다."라고 표시되어 있습니다. 이것이 특별한 클래스를 만드는 이유 일 가능성이 높습니다. 컴파일러에 의해 특별히 처리됩니다.
RB.

1
@RB .: 잘못되었습니다. 의미이 논리 System.Object입니다 하지 :이 유효한 경우, "특별한 클래스" public class X : System.Object { },하지만 System.Object여전히 "특별한 클래스"입니다.
Mints97 2015-04-30

답변:


106

Roslyn 소스 코드에서는 하드 코딩 된 유형 목록처럼 보입니다.

switch (type.SpecialType)
{
    case SpecialType.System_Object:
    case SpecialType.System_ValueType:
    case SpecialType.System_Enum:
    case SpecialType.System_Delegate:
    case SpecialType.System_MulticastDelegate:
    case SpecialType.System_Array:
        // "Constraint cannot be special class '{0}'"
        Error(diagnostics, ErrorCode.ERR_SpecialTypeAsBound, syntax, type);
        return false;
}

출처 : Binder_Constraints.cs IsValidConstraintType
GitHub 검색을 사용하여 찾았습니다. "제약 조건은 특수 클래스가 될 수 없습니다."


1
@kobi 702는 컴파일러 출력 (이 질문은 인용하지 않음) 및 기타 답변에서 볼 수 있듯이 컴파일러 오류 CS0702가됩니다.
AakashM 2015

1
@AakashM-감사합니다! 나는 컴파일을 시도했지만 어떤 이유로 오류 번호를 얻지 못했습니다. 그런 다음 알아내는 데 거의 5 분이 걸렸고 댓글을 편집 할 시간이 충분하지 않았습니다. 슬픈 이야기.
Kobi

1
@Kobi : 출력 창 을 살펴보면 정확한 컴파일러 오류 코드 번호를 찾을 수 CS0702있습니다.
Tim Schmelter 2015

9
이제 진짜 질문은 왜이 특별한 수업 이냐는 것입니다.
다윗은 분석 재개 모니카 말한다

@DavidGrinberg 아마도 이유는 이러한 유형에서 직접 (제외 object) 상속 할 수 없거나 적어도 이와 관련이 있기 때문일 수 있습니다 . 또한 where T : Array대부분의 사람들이 원하는 것이 아닌 T로 Assay를 전달할 수 있습니다.
IllidanS4는 Monica가

42

비슷한 질문에 대해 2008 년 Jon Skeet의 의견을 찾았습니다 . System.Enum제약 조건 지원 되지 않는 이유입니다 .

나는 이것이 약간 벗어난 주제라는 것을 알고 있지만 그는 Eric Lippert (C # 팀)에게 그것에 대해 물었고 그들은이 답변을 제공했습니다.

우선, 당신의 추측이 맞습니다. 제약 조건에 대한 제한은 CLR이 아니라 언어의 큰 인공물입니다. (이러한 기능을 수행하면 열거 가능한 유형이 지정되는 방식과 관련하여 CLR에서 변경하고 싶은 몇 가지 사소한 사항이 있지만 대부분은 언어 작업입니다.)

둘째, 저는 개인적으로 델리게이트 제약, 열거 제약 및 오늘날 불법적 인 제약 조건을 지정하는 기능을 갖고 싶습니다. 컴파일러가 사용자를 자신으로부터 구하려고하기 때문입니다. (즉, 봉인 된 유형을 제약 조건으로 합법화하는 등의 작업입니다.)

그러나 일정 제한으로 인해 이러한 기능을 다음 버전의 언어로 제공하지 못할 수 있습니다.


10
@YuvalItzchakov-Github \ MSDN을 인용하는 것이 더 낫습니까? C # 팀은 문제 또는 이와 유사한 문제에 대해 구체적인 답변을 제공했습니다. 정말 누구에게도 해를 끼칠 수 없습니다. Jon Skeet이 방금 인용했으며 C #에 도달했을 때 매우 신뢰할 수 있습니다.
Amir Popovich

5
화낼 필요가 없습니다. 나는 이것이 유효한 대답이 아니라는 것을 의미하지 않았다 :) 단지 jonskeet 인 재단에 대한 나의 생각을 공유하고 있었다; p
Yuval Itzchakov

40
FYI BTW 나는 당신이 거기에서 인용하고있는 나라고 생각합니다. :-)
Eric Lippert 2015

2
@EricLippert-견적을 더욱 신뢰할 수 있습니다.
Amir Popovich

응답의 링크 도메인이 죽었습니다.
Pang

25

MSDN 에 따르면 정적 클래스 목록입니다.

컴파일러 오류 CS0702

제약 조건은 특수 클래스 '식별자'일 수 없습니다. 다음 유형은 제약 조건으로 사용할 수 없습니다.

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.

4
멋지다, 정답 인 것 같다, 좋은 찾기! 하지만 System.MulticastDelegate목록 에는 어디에 있습니까?
Mints97 2015

8
@ Mints97 : 모름, 아마도 문서 부족?
Tim Schmelter 2015

이러한 클래스에서 상속 할 수없는 것처럼 보입니다.
David Klempfner

14

C # 4.0 언어 사양 (코드 : [10.1.5] 유형 매개 변수 제약 조건)에 따라 다음 두 가지를 알려줍니다.

1] 유형은 객체가 아니어야합니다. 모든 유형이 객체에서 파생되기 때문에 이러한 제약 조건은 허용되는 경우 효과가 없습니다.

2] T에 기본 제약 조건이나 유형 매개 변수 제약 조건이없는 경우 유효한 기본 클래스는 객체입니다.

제네릭 클래스를 정의 할 때 클라이언트 코드가 클래스를 인스턴스화 할 때 유형 인수에 사용할 수있는 유형의 종류에 제한을 적용 할 수 있습니다. 클라이언트 코드가 제약 조건에서 허용하지 않는 형식을 사용하여 클래스를 인스턴스화하려고하면 결과는 컴파일 타임 오류입니다. 이러한 제한을 제약이라고합니다. 제약 조건은 where 문맥 키워드를 사용하여 지정됩니다. 제네릭 유형을 참조 유형으로 제한하려면 : 클래스를 사용하십시오.

public class Gen<T> where T : class
{
}

이것은 제네릭 유형이 int 또는 struct 등과 같은 값 유형이되는 것을 금지합니다.

또한 제약 조건은 특수 클래스 '식별자'가 될 수 없습니다. 다음 유형은 제약 조건으로 사용할 수 없습니다.

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.

12

프레임 워크에는 특수 특성을 파생 된 모든 유형에 효과적으로 전달 하지만 그 특성 자체를 소유하지는 않는 특정 클래스가 있습니다 . CLR 자체는 이러한 클래스를 제약 조건으로 사용하는 것을 금지하지 않지만, 이에 제한되는 제네릭 형식은 구체적인 형식과 달리 상속되지 않은 특성을 얻지 못합니다. C #의 작성자는 이러한 동작이 일부 사람들에게 혼란을 줄 수 있고 유용성을 보지 못하기 때문에 이러한 제약 조건이 CLR 에서처럼 동작하도록 허용하기보다는 금지해야한다고 결정했습니다.

예를 들어 다음과 같이 쓸 수있는 경우 : void CopyArray<T>(T dest, T source, int start, int count); 하나는 유형의 인수를 예상하는 메소드 dest와 전달할 수 있습니다 . 또한, 하나는 컴파일시의 검증이를 얻을 것 와 호환되는 배열 형했지만, 하나는 사용하여 배열의 액세스 요소 수 없을 것 연산자.sourceSystem.Arraydestsource[]

Array제약 조건 으로 사용할 수없는 것은 대부분 해결하기가 매우 쉽습니다 void CopyArray<T>(T[] dest, T[] source, int start, int count). 이전 방법이 작동하는 거의 모든 상황에서 작동하기 때문입니다. 그러나 약점이 있습니다. 전자의 방법은 System.Array인수가 호환되지 않는 배열 유형 인 경우를 거부하면서 인수 중 하나 또는 둘 모두가 유형 인 시나리오에서 작동 합니다. 두 인수가 모두 유형 인 오버로드를 추가하면 System.Array코드가 허용해야하는 추가 사례를 수락 할 수 있지만 허용해서는 안되는 사례를 잘못 수락하게됩니다.

나는 대부분의 특수 제약을 불법화하기로 결정했습니다. 의미 론적 의미가 0 인 유일한 것은 System.Object[제약으로서 합법적이라면 어떤 것이라도 그것을 만족시킬 것이기 때문에] 일 것입니다. System.ValueType유형의 참조는 ValueType값 유형과 실제로 공통점이 많지 않기 때문에 유용 하지 않을 수 있지만 Reflection과 관련된 경우에는 그럴듯하게 가치가있을 수 있습니다. 모두 System.EnumSystem.Delegate진짜 용도가 것이지만, C #의 창조자들을 생각하지 않았기 때문에 그들이 더 좋은 이유에 대해 금지하고 있습니다.


10

다음은 C # 4th Edition을 통해 CLR에서 찾을 수 있습니다.

주요 제약

유형 매개 변수는 0 개의 1 차 제약 조건 또는 1 개의 1 차 제약 조건을 지정할 수 있습니다. 기본 제약 조건은 봉인되지 않은 클래스를 식별하는 참조 형식 일 수 있습니다. System.Object , System.Array , System.Delegate , System.MulticastDelegate , System.ValueType , System.Enum 또는 System.Void 특수 참조 유형 중 하나를 지정할 수 없습니다 . 참조 형식 제약 조건을 지정할 때 지정된 형식 인수가 같은 형식이거나 제약 조건 형식에서 파생 된 형식이 될 것이라고 컴파일러에 약속합니다.


참조 : C #의 LS 섹션 10.1.4.1을 : 클래스 형식의 직접 기본 클래스는 다음과 같은 유형의가 아니어야합니다 : System.Array, System.Delegate, System.MulticastDelegate, System.Enum, 또는 System.ValueType. 또한 일반 클래스 선언은 System.Attribute직접 또는 간접 기본 클래스로 사용할 수 없습니다 .
Jeroen Vannevel

5

"특별한 클래스"/ "특별한 유형"에 대한 공식적인 정의가 있다고 생각하지 않습니다.

"일반"유형의 의미 체계와 함께 사용할 수없는 유형으로 생각할 수 있습니다.

  • 직접 인스턴스화 할 수 없습니다.
  • 사용자 정의 유형을 직접 상속 할 수 없습니다.
  • 그들과 함께 작동하는 컴파일러 마법이 있습니다 (선택적으로);
  • 적어도 쓸모없는 인스턴스의 직접적인 사용 (선택적으로, 위에서 제네릭을 만들었다 고 상상해보십시오. 어떤 제네릭 코드를 작성할 것입니까?)

추신 System.Void목록에 추가하겠습니다 .


2
System.Void일반 제약 조건으로 사용될 때 완전히 다른 오류를 제공합니다 =)
Mints97

@ Mints97 : 사실. 그러나 질문이 "특별"에 관한 것이라면 예, void매우 특별합니다. :)
Dennis

@Dennis : 제한된 유형의 매개 변수가 두 개있는 코드는 데이터를 한 곳에서 다른 곳으로 옮기는 System.Array것과 같은 방법을 사용할 수 있습니다 Array.Copy. 형태의 파라미터를 가지는 코드에 제약을 System.Delegate사용할 수있을 것입니다 Delegate.Combine그들에 적절한 형식으로 결과를 캐스팅 . 제네릭 알려진 유형을 효과적으로 사용 Enum하면 이러한 유형에 대해 Reflection을 한 번 사용하지만 제네릭 HasAnyFlag메서드는 비 제네릭 메서드보다 10 배 더 빠를 수 있습니다.
supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.