其中t:类泛型约束和const值声明

时间:2013-07-23 18:18:42

标签: c# generics const

根据10.4 Constants中的C#规范:

  

常量声明中指定的类型必须 sbyte,byte,   short,ushort,int,uint,long,ulong,char,float,double,decimal,   bool,string,enum-type,或引用类型。每个   constant-expression必须产生目标类型或类型的值   可以通过隐式转换转换为目标类型   (第6.1节)。

为什么我不能这样做:

public class GenericClass<T>
    where T : class
{
    public const T val = null;
}

这应该是可能的,因为:

  • where T : class表示The type argument must be a reference type; this applies also to any class, interface, delegate, or array type(来自MSDN
  • 它满足规范中的另一个词:string以外的参考类型常量的唯一可能值是null

任何可能的解释?

2 个答案:

答案 0 :(得分:0)

可能的解释

考虑CLR如何初始化泛型类的static成员,或者在泛型类型上调用静态构造函数时。通常,首次加载程序时会发生静态初始化;但是,泛型类在第一次创建该类的实例时初始化其静态成员。

请记住,泛型类不是单一类型;在类型声明中传递的每个T都在创建一个新类型。

现在考虑一个const表达式,它需要在编译时进行求值。虽然T被约束为一个类,因此它可以接收值null,但是在运行时创建类之前,变量val在内存中不存在。

例如,考虑const T val是否有效。然后我们可以使用代码中的其他地方:

GenericClass<string>.val
GenericClass<object>.val

修改

虽然两个表达式的值都为null,但前者的类型为string,后者的类型为object。为了使编译器执行替换,它需要知道有问题的常量的类型定义。

约束可以在编译时强制执行,但是开放式泛型在运行时才会转换为封闭的泛型。因此,GenericClass<object>.val不能存储在编译器的本地内存中以执行替换,因为编译器不会实例化泛型类的闭合形式,因此不知道将常量表达式实例化为什么类型。

答案 1 :(得分:0)

Eric Lippert承认这是一个错误,应该允许:

  

在我看来,你发现了一个错误;要么bug在规范中,应该明确地调出类型参数不是有效类型,或者bug在编译器中,应该允许它。