究竟是什么"特殊班级"?

时间:2015-04-30 07:40:43

标签: c# class generics generic-constraints

无法获得以下内容进行编译:

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

错误

  

约束不能是特殊的类`System.Array&#39;

我开始想知道,是什么&#34;特殊课程&#34;?

人们在通用约束中指定System.Enum时似乎经常会遇到同样的错误。我在System.ObjectSystem.DelegateSystem.MulticastDelegateSystem.ValueType也得到了相同的结果。

还有更多吗?我找不到关于&#34;特殊课程和#34;的任何信息。在C#。

此外,对于那些我们不能将它们用作泛型类型约束的类, 是如此特殊?

7 个答案:

答案 0 :(得分:105)

从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搜索:"A constraint cannot be special class"

答案 1 :(得分:41)

我在2008年发现了Jon Skeet关于类似问题的评论: 为什么System.Enum约束不支持

我知道这有点偏离,但他向Eric Lippert(C#团队)询问了这个问题,他们提供了这个答案:

  

首先,你的推测是正确的;对约束的限制   这是语言的基本文物,而不是CLR。 (均   我们要做这些功能会有一些我们想要的小事   关于如何指定可枚举类型的CLR更改,但是   这大部分都是语言工作。)

     

其次,我个人喜欢委托约束,枚举   约束,以及指定非法约束的能力   今天因为编译器试图从你自己那里拯救你。 (那   是,使密封类型合法作为约束,等等。)

     

但是,由于时间安排的限制,我们可能无法做到   将这些功能纳入下一版本的语言。

答案 2 :(得分:25)

根据MSDN,它是一个静态的类列表:

编译器错误CS0702

约束不能是特殊类'标识符'以下类型不能用作约束:

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

答案 3 :(得分:14)

根据C#4.0语言规范(编码:[10.1.5]类型参数约束)说明两件事:

  

1]类型不能是对象。因为所有类型都来自对象,   如果允许,这样的约束就没有效果。

     

2]如果T没有主要约束或类型参数约束,则其有效   基类是对象。

定义泛型类时,可以对实例化类时客户端代码可用于类型参数的类型类型应用限制。如果客户端代码尝试使用约束不允许的类型来实例化您的类,则结果是编译时错误。这些限制称为约束。使用where contextual关键字指定约束。 如果要将泛型类型约束为引用类型,请使用:class。

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

这将禁止泛型类型为值类型,例如int或struct等。

此外,约束不能是特殊类别的标识符&#39;以下类型不能用作约束:

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

答案 4 :(得分:12)

框架中有某些类可以有效地将特殊特征传递给从它们派生的所有类型但不具备这些特征。 CLR本身没有禁止将这些类用作约束,但是限制它们的泛型类型不会像具体类型那样获得非继承特性。 C#的创建者决定,因为这样的行为可能会使某些人感到困惑,并且他们没有看到任何有用的东西,他们应该禁止这些限制,而不是让他们像在CLR中那样行事。

例如,如果允许一个人写:void CopyArray<T>(T dest, T source, int start, int count);一个人可以将destsource传递给期望类型为System.Array的参数的方法;此外,人们将获得destsource是兼容的数组类型的编译时验证,但是使用[]运算符无法访问数组的元素。

无法使用Array作为约束通常很容易解决,因为void CopyArray<T>(T[] dest, T[] source, int start, int count)几乎适用于前一种方法可行的所有情况。但它有一个缺点:前一种方法可以在一个或两个参数都是System.Array类型的情况下工作,同时拒绝参数是不兼容的数组类型的情况;添加一个重载,其中两个参数都是类型System.Array将使代码接受它应该接受的其他情况,但也会使它错误地接受它不应该接受的情况。

我发现决定禁止大多数特殊限制令人厌烦。唯一没有语义意义的是System.Object [因为如果这是合法的约束,任何东西都会满足它]。 System.ValueType可能不会非常有用,因为类型ValueType的引用与值类型并没有多少共同之处,但在涉及Reflection的情况下它可能有一些价值。 System.EnumSystem.Delegate都有一些实际用途,但由于C#的创建者没有想到它们,因此没有充分的理由将它们视为非法。

答案 5 :(得分:10)

以下内容可在CLR中通过C#第4版找到:

主要约束

类型参数可以指定零主要约束或一个主要约束。小学 约束可以是标识未密封的类的引用类型。你不能指定一个 以下特殊引用类型: System.Object System.Array System.Delegate , 的 System.MulticastDelegate 下, System.ValueType System.Enum System.Void 。 指定引用类型约束时,您承诺编译器指定类型 参数将是相同类型或从约束类型派生的类型。

答案 6 :(得分:5)

我不认为,特殊类别&#34; /&#34;特殊类型&#34;有正式的定义。

你可能会认为它们是一种类型,它们不能用于#34;常规&#34;的语义。类型:

  • 你不能直接实例化它们;
  • 您无法直接从中继承自定义类型;
  • 有一些编译器魔法可以使用它们(可选);
  • 他们的实例的直接使用至少是无用的(可选;想象一下,你上面创建了通用的,你要编写什么通用代码?)

P.S。我将System.Void添加到列表中。