5

根据 C# 规范10.4 Constants

常量声明中指定的类型必须是sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、bool、string、枚举类型或引用类型。每个常量表达式必须产生一个目标类型的值,或者可以通过隐式转换(第 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
  • 它满足规范中的另一个词:除了is之外的引用类型常量的唯一可能值stringnull

有什么可能的解释吗?

4

2 回答 2

0

可能的解释

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

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

现在考虑一个const表达式,它需要在编译时进行评估。尽管 T 被限制为一个类,因此它可以接收 null 值,但val在运行时创建该类之前,该变量不存在于内存中。

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

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

编辑

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

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

于 2013-07-24T04:37:58.113 回答
0

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

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

于 2013-08-20T05:22:24.617 回答