什么是“特级”?

没有得到如下所示的东西来编译:

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

与错误

约束不能是特殊的类“System.Array”

我开始怀疑,什么 “特殊class”?

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

他们有更多吗? 我在C#中找不到“特殊类”的任何信息。

另外,这些类别有什么特别之处,我们不能将它们用作generics约束?

从Roslyn源代码,它看起来像一个硬编码types的列表:

 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
我发现它使用GitHubsearch: “一个约束不能是特殊的类”

我从2008年发现了一个类似问题的Jon Skeet评论:为什么支持System.Enum约束。

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

首先,你的猜想是正确的。 对约束的限制大体上是语言的文物,而不是CLR。 (如果我们要做这些function,那么我们希望在CLR中改变一些小的东西,说明如何指定可枚举types,但大多数情况下这将是语言工作。)

其次,我个人喜欢委托约束,枚举约束,并且指定约束是非法的,因为编译器试图从你自己中解救出来。 (也就是说,将密封types合法化为约束,等等)。

但是,由于计划的限制,我们可能无法将这些functionjoin下一版本的语言中。

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

编译器错误CS0702

约束不能是特殊类“标识符”以下types不能用作约束:

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

按照C#4.0语言规范(编码:[10.1.5]types参数约束)告诉了两件事:

1]types不能是对象。 因为所有types都是从对象派生的,所以如果这个约束被允许的话,这个约束就不会有效果。

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

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

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

这将禁止genericstypes是一个值types,如int或结构等

此外,约束不能是特殊的类“标识符”以下types不能用作约束:

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

框架中有一些类将特殊的特性有效地传递给所有从它们派生出来的types, 但是它们本身并不具备这些特性 。 CLR本身并不禁止使用这些类作为约束,但是约束它们的generics将不会像具体types那样获得非inheritance的特性。 C#的创造者决定,因为这样的行为可能会混淆一些人,而他们没有看到任何有用的东西,他们应该禁止这样的约束,而不是让他们像CLR那样行事。

例如,如果允许一个人写: void CopyArray<T>(T dest, T source, int start, int count) ; 人们可以将destsource传递给需要System.Arraytypes参数的方法; 进一步说,人们会得到编译时validationdestsource是兼容的数组types,但是不能使用[]运算符访问数组的元素。

因为void CopyArray<T>(T[] dest, T[] source, int start, int count)在几乎所有的情况下都可以工作,工作。 然而,它确实有一个弱点:前一种方法可以在一个或两个参数是System.Array情况下工作,同时拒绝参数是不兼容的数组types的情况; 在两个参数都是System.Arraytypes的情况下增加一个重载会使代码接受它应该接受的其他情况,但也会使它错误地接受它不应该的情况。

我觉得大部分特殊的限制是令人讨厌的。 唯一没有语义含义的是System.Object [因为如果这是合法的约束,任何东西都可以满足它]。 System.ValueType可能不会非常有用,因为typesValueType引用与值types并没有多less共同之处,但在涉及Reflection的情况下,它可能会有一定的价值。 System.EnumSystem.Delegate都有一些真正的用途,但是由于C#的创build者没有想到他们,因此没有理由被取缔。

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

主要限制

types参数可以指定零主要约束或一个主要约束。 主要约束可以是标识不被密封的类的引用types。 您不能指定以下特殊引用types之一: System.ObjectSystem.ArraySystem.DelegateSystem.MulticastDelegateSystem.ValueTypeSystem.EnumSystem.Void 。 在指定引用types约束时,您希望编译器指定的types实参将具有相同types或从约束types派生的types。

我不认为存在“特殊类”/“特殊types”的官方定义。

你可以把它们想成一个types,它不能用于“常规”types的语义:

  • 你不能直接实例化它们;
  • 你不能直接从它们inheritance自定义types;
  • 有一些编译器的魔术可以与他们(任意)一起工作;
  • 直接使用它们的实例至less是无用的(可选地,想象一下,你已经创build了通用的上面,你会写什么样的通用代码?)

PS我会添加System.Void到列表中。