简体   繁体   English

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

[英]where t : class generic constraint and const value declaration

According to C# specification in 10.4 Constants : 根据10.4 Constants C#规范:

The type specified in a constant declaration must be sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, an enum-type, or a reference-type. 常量声明中指定的类型必须是 sbyte,byte,short,ushort,int,uint,long,ulong,char,float,double,decimal,bool,string,enum-type 或reference-type。 Each constant-expression must yield a value of the target type or of a type that can be converted to the target type by an implicit conversion (§6.1). 每个常量表达式必须生成目标类型或可通过隐式转换(第6.1节)转换为目标类型的类型的值。

Why then I can't do following: 为什么我不能做以下事情:

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

That should be possible, because: 这应该是可能的,因为:

  • where T : class means, that The type argument must be a reference type; this applies also to any class, interface, delegate, or array type where T : class表示, The type argument must be a reference type; this applies also to any class, interface, delegate, or array type The type argument must be a reference type; this applies also to any class, interface, delegate, or array type (from MSDN ) The type argument must be a reference type; this applies also to any class, interface, delegate, or array type (来自MSDN
  • it satisfies another words from specification: the only possible value for constants of reference-types other than string is null . 它满足规范中的另一个单词: 除了string之外,引用类型常量的唯一可能值为null

Any possible explanation? 任何可能的解释?

Possible Explanation 可能的解释

Consider how the CLR initializes static members of generic classes or when it invokes static constructors on generic types. 考虑CLR如何初始化泛型类的static成员,或者在泛型类型上调用静态构造函数时。 Normally, static initialization occurs when the program is first loaded; 通常,首次加载程序时会发生静态初始化; however, generic classes initialize their static members the first time an instance of that class is created. 但是,泛型类在第一次创建该类的实例时初始化其静态成员。

Bear in mind that a generic class is not a single type; 请记住,泛型类不是单一类型; every single T that gets passed in the type declaration is creating a new type. 在类型声明中传递的每个T都在创建一个新类型。

Now then consider a const expression, which has the requirement to be evaluated at compile-time. 现在考虑一个const表达式,它需要在编译时进行求值。 Although T is constrained as a class, and therefore it can receive the value null, the variable val does not exist in memory until the class has been created at runtime. 尽管T被约束为一个类,因此它可以接收值null,但是在运行时创建类之前,变量val不存在于内存中。

For example, consider if the const T val were valid. 例如,考虑const T val是否有效。 Then elsewhere in the code we could use: 然后我们可以使用代码中的其他地方:

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

Edit 编辑

Although both expressions would have the value null , the former is of type string and the latter is of type object . 虽然两个表达式的值都为null ,但前者的类型为string ,后者的类型为object In order for the compiler to perform substitution, it needs to know the type definitions of the constants in question. 为了使编译器执行替换,它需要知道有问题的常量的类型定义。

Constraints may be enforced at compile-time, but open generics are not converted into closed generics until runtime. 约束可以在编译时强制执行,但是开放泛型在运行时之前不会转换为封闭的泛型。 Therefore, GenericClass<object>.val cannot be stored in the compiler's local memory to perform the substitution because the compiler does not instantiate the closed form of the generic class, and thus does not know what type to instantiate the constant expression to. 因此, GenericClass<object>.val不能存储在编译器的本地内存中以执行替换,因为编译器没有实例化泛型类的闭合形式,因此不知道将常量表达式实例化的类型。

Eric Lippert admitted it is a bug, and it should be allowed: Eric Lippert承认这是一个bug,应该允许:

It looks to me like you've found a bug; 它看起来像你发现了一个错误; either the bug is in the specification, which should explicitly call out that type parameters are not valid types, or the bug is in the compiler, which should allow it. 要么bug在规范中,应该明确地调出类型参数不是有效类型,或者bug在编译器中,应该允许它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM