什么是"特殊班级"?

Min*_*s97 113 c# generics class generic-constraints

在未能获得类似以下内容的编译之后:

public class Gen<T> where T : System.Array
{
}
Run Code Online (Sandbox Code Playgroud)

有错误

约束不能是特殊的类`System.Array'

我开始疑惑,究竟什么 "特殊班级"?

当人们System.Enum在泛型约束中指定时,人们似乎经常会遇到同样的错误.我得到了相同的结果System.Object,System.Delegate,System.MulticastDelegateSystem.ValueType也.

还有更多吗?我在C#中找不到关于"特殊类"的任何信息.

此外,什么如此特殊的,我们不能把它们作为一个泛型类型约束类?

Kob*_*obi 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;
}
Run Code Online (Sandbox Code Playgroud)

来源:Binder_Constraints.cs IsValidConstraintType
我发现它使用GitHub搜索:"约束不能是特殊类"

  • 所以现在真正的问题是_why_是这些特殊类吗? (8认同)

Ami*_*ich 41

为什么:我在一个类似的问题找到了乔恩斯基特评论从2008年System.Enum的约束支持.

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

首先,你的猜想是正确的; 对约束的限制大体上是语言的假象,而不是CLR.(如果我们要做这些功能,我们希望在CLR中改变一些关于如何指定可枚举类型的小事,但大多数情况下这将是语言工作.)

其次,我个人喜欢委托约束,枚举约束,以及指定今天非法的约束的能力,因为编译器试图将你从自己身上拯救出来.(也就是说,使密封类型合法作为约束,依此类推.)

但是,由于计划限制,我们可能无法将这些功能纳入下一版本的语言.

  • 仅供参考我认为那是你在那里引用的.:-) (40认同)
  • 人们仅仅引用@JonSkeet得分.惊人. (20认同)
  • @YuvalItzchakov - 引用Github\MSDN更好?C#团队就这个问题或类似的问题给出了具体的答案.它不会真正伤害任何人.Jon Skeet刚刚引用它们,并且在进入C#时非常可靠. (10认同)
  • 无需心烦意乱.我并不是说这不是一个有效的答案:)只是在jonskeet的基础上分享我的想法; p (5认同)
  • @EricLippert-这使报价更加可靠。 (2认同)

Tim*_*ter 25

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

编译器错误CS0702

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

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

  • @ Mints97:不知道,也许缺乏文档? (8认同)
  • 很酷,似乎是正确的答案,很好找!但是列表中的`System.MulticastDelegate`在哪里? (4认同)

Rah*_*ate 14

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

1]类型不能是对象.因为所有类型都是从对象派生的,所以如果允许这样的约束就没有效果.

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

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

public class Gen<T> where T : class
{
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


sup*_*cat 12

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

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

无法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#的创造者没有想到他们的他们是非法的没有很好的理由.


Cla*_*o P 10

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

主要约束

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


Den*_*nis 5

我不认为,"特殊类别"/"特殊类型"存在任何官方定义.

您可以将它们视为一种类型,它们不能与"常规"类型的语义一起使用:

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

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

  • 当用作通用约束时,`System.Void`给出完全不同的错误=) (2认同)