[c#] “특별 수업”이란 정확히 무엇입니까?

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

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

오류와 함께

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

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

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

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

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



답변

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 검색을 사용하여 찾았습니다. “제약 조건은 특수 클래스가 될 수 없습니다.”


답변

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

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

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

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

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


답변

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

컴파일러 오류 CS0702

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

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

답변

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.

답변

프레임 워크에는 특수 특성을 파생 된 모든 유형에 효과적으로 전달 하지만 그 특성 자체를 소유하지는 않는 특정 클래스가 있습니다 . 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 #의 창조자들을 생각하지 않았기 때문에 그들이 더 좋은 이유에 대해 금지하고 있습니다.


답변

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

주요 제약

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


답변

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

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

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

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