什么是“特级”?
没有得到如下所示的东西来编译:
public class Gen<T> where T : System.Array { }
与错误
约束不能是特殊的类“System.Array”
我开始怀疑,什么是 “特殊class”?
当他们在通用约束中指定System.Enum
时,人们似乎经常会遇到同样的错误。 我也得到了与System.Object
, System.Delegate
, System.MulticastDelegate
和System.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)
; 人们可以将dest
和source
传递给需要System.Array
types参数的方法; 进一步说,人们会得到编译时validationdest
和source
是兼容的数组types,但是不能使用[]
运算符访问数组的元素。
因为void CopyArray<T>(T[] dest, T[] source, int start, int count)
在几乎所有的情况下都可以工作,工作。 然而,它确实有一个弱点:前一种方法可以在一个或两个参数是System.Array
情况下工作,同时拒绝参数是不兼容的数组types的情况; 在两个参数都是System.Array
types的情况下增加一个重载会使代码接受它应该接受的其他情况,但也会使它错误地接受它不应该的情况。
我觉得大部分特殊的限制是令人讨厌的。 唯一没有语义含义的是System.Object
[因为如果这是合法的约束,任何东西都可以满足它]。 System.ValueType
可能不会非常有用,因为typesValueType
引用与值types并没有多less共同之处,但在涉及Reflection的情况下,它可能会有一定的价值。 System.Enum
和System.Delegate
都有一些真正的用途,但是由于C#的创build者没有想到他们,因此没有理由被取缔。
通过C#第4版可以在CLR中find以下内容:
主要限制
types参数可以指定零主要约束或一个主要约束。 主要约束可以是标识不被密封的类的引用types。 您不能指定以下特殊引用types之一: System.Object , System.Array , System.Delegate , System.MulticastDelegate , System.ValueType , System.Enum或System.Void 。 在指定引用types约束时,您希望编译器指定的types实参将具有相同types或从约束types派生的types。
我不认为存在“特殊类”/“特殊types”的官方定义。
你可以把它们想成一个types,它不能用于“常规”types的语义:
- 你不能直接实例化它们;
- 你不能直接从它们inheritance自定义types;
- 有一些编译器的魔术可以与他们(任意)一起工作;
- 直接使用它们的实例至less是无用的(可选地,想象一下,你已经创build了通用的上面,你会写什么样的通用代码?)
PS我会添加System.Void
到列表中。