.Net把泛型类型的静态字段值存储在哪里?

10
以下代码允许我为每种类型 T 存储一个值:
public static class MyDict<T> {
    public static T Value;
}

我可以存储与类型数量相同的值,编译器不知道我将使用哪些类型。这些静态字段值存储在哪里?
更新: 显然它存储在内存中,但我想了解这个内存。它是堆吗?是一些特殊的CLR内存吗?它被称为什么?还有什么其他东西以这种方式存储?
更新2: JITter为MyDict的所有引用类型参数生成一个单独的实现MyDict<__Canon>。 然而,这些值是分别存储的。我想每个类型参数仍然有一些针对该类型参数的结构,虚函数表链接到JITted MyDict<__Canon>,而字段是单独的。 我是正确的吗?

8
真正的答案是,“编译器想存储它们在哪里,如果你不喜欢,你打算怎么办?” - John Saunders
1
你说的“where”是什么意思?难道“RAM”不是你要找的答案吗? - ddavison
2
MyDict<T> 不是一个完全定义的类型。每个完全定义的 MyDict<T> 类型将拥有自己独特的 Value 实例(例如,MyDict<string>MyDict<object>MyDict<int> 可以具有唯一的 Value 值)。我没有将这个作为答案,因为我觉得这并不是你要问的问题,但我认为这仍然是有用的。 - Brian Ball
2
@BrianBall 我认为那就是问题。 - asawyer
3
我不知道答案,但我觉得这个问题很有趣。请不要关闭。特别有趣的是,针对带有引用类型参数的所有构造类型,都共享JIT编译代码。 - erikkallen
显示剩余4条评论
2个回答

15
这些静态属性值存储在CLR选择的内存位置中,显然是存储在内存中,但我想了解一下这个内存。如果你根据这个问题的答案做出编程决策,那么你肯定做错了什么。它不是堆栈或寄存器,当然不是。是一些特殊的CLR内存,称为高频堆(high frequency heap),任何CLR认为会频繁访问的东西都可以存储在这里,包括vtables、接口映射结构、方法描述等。我们现在涉及到实现细节。对于所有引用类型参数的MyDict,JITter会生成单个实现MyDict<__Canon>,但值被单独存储。 "值"是指每个构造类型的静态字段值,而且对于每个类型参数,仍然有一些特定于类型的结构存储数据。vtable链接到JITted MyDict<__Canon>,字段是分开的。作者无法理解最后一个问题的意思,因此无法确认其正确性。询问者是否存在某种存储机制来关联泛型类型C和给定的构造C与C的给定静态字段的相应值。我们可以将其视为查找,其中“键”是元组(C,Foo,field),而“值”是字段的值。是否存在类似的存储机制,其中键为(C,某个任意对象,field)?答案是否定的,如果需要这样的机制,就需要自己构建它。

如果您想查看CLR是如何实现的,可以在此处查看共享源代码CLI - Scott Chamberlain
是的,显然它存储在内存中,但也许那个内存有一些名称。我还想知道是否有一种方法可以拥有像那样的每个对象存储。即不是“通用类型+T”,而是“对象+T”。 - Ark-kun
@Ark-kun,“object + T”版本(实际上只是“object”版本,“T”无关紧要)就是非静态实例变量。 - Scott Chamberlain
1
@ScottChamberlain 不是的。正如你所说,实例字段只是“对象索引”。泛型类型的静态字段是“类型+类型”索引(Type1<TA1>.ValueType1<TA2>.ValueType2<TA1>.Value不同)。我在评论中问的是一个值,它是“对象+类型”索引。就像Dictionary<Type, Object>的实例一样,但是在编译时确定。 - Ark-kun
@Ark-kun:我已经回答了你的后续问题。 - Eric Lippert
显示剩余2条评论

5
MyDict<T>不是一个完全定义的类型。每个完全定义的MyDict<T>类型都将具有其自己独特的Value实例(例如,MyDict<string>���MyDict<object>MyDict<int>可以具有独特的Value值)。
此外,这并不特殊,因为Value的类型是T,即使Value的类型是DateTime,每个完全定义的类型仍将有其自己的静态值实例。

1
是的,就像我所写的那样,这些实例是不同的。但是我想知道值存储在哪里。非泛型类型的静态字段是单例的,实例字段是每个实例的。但是泛型类型的静态字段是每个类型参数的。 - Ark-kun
从这个角度看, Dict<T> 不是一种类型(不完全准确,但为了争论的缘故,我们假设它是真的),它是一个部分。 Dict<string> 是一种类型, Dict<Foo> 也是一种类型。你可能会称它们为 DictStringDictFoo。泛型提供了一种定义部分类型和使用占位符(如 T)作为空白的方法。运行时自动填充这些空白,以节省大量的复制/粘贴。 - Brian Ball
还有,只是提醒一下,并非所有静态变量都是单例的。如果你使用ThreadStaticAttribute来修饰一个静态变量,那么每个线程上都会有该静态字段的一个实例。 - Brian Ball

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接