c# const成员是如何在内存中分配的

本文关键字:内存 分配 const 成员 | 更新日期: 2023-09-27 18:02:19

问题的标题不言自明。我想知道声明为const的成员是否对类的所有实例都是单例的,或者每个实例都有自己的副本。

我读过一些关于const的问题,但其中大多数是指方法内的const变量。

c# const成员是如何在内存中分配的

c#常量在公共语言结构中用literal约束作为字段来实现。查找ECMA-335 §I.8.6.1.2提供了明确的答案(强调我的):

文字约束承诺位置的值为实际上是一个内置类型的固定值。指定为约束的一部分。编译器需要替换所有引用位置及其值,因此需要[虚拟执行系统]不为位置分配空间。这个约束,在逻辑上适用于任何位置,只能放置在静电场上复合类型。这样标记的字段是不允许的从CIL中引用(它们应内联到它们的常数值)编译时),,但可以使用反射和工具直接处理元数据

因此,编译器必须将const字段的值直接复制到指令流中(通常使用ldc.*指令)。它们不存在于可引用的位置,但需要在元数据中并通过反射可用。它们可以像静态字段一样实现,但不必如此。

常量通常是可以在编译时求值的,编译器可能会用求值来替换它。

Const也意味着static(见下面的链接)

常数表达式是可以在处完全求值的表达式编译时间。的常数唯一可能的值引用类型为string和null。

源:

c#静态变量和常量变量内存

c#中const的内存分配 c#中const字段使用更少的内存吗?

const意味着static,所以每个类只有一个实例。

编辑:添加参考

常量在编译时解析,常量的实际值存储在编译后的DLL中,代替对该常量的引用。

此外,该常量作为类的成员保存在DLL中。这允许外部dll引用公共常量。但是,外部引用在编译时也会转换为常量值。

常量的编译属性的一个分支意味着,如果DLL1引用外部DLL2中的常量,并且DLL2中的常量定义发生了变化,那么DLL1 将不会具有更新的值,除非它也被重新编译。

如果你想解决这个问题,你最好使用公共属性返回常量。有关更多信息,请参阅此问题的答案。

我用。net Reflector确认了上述行为

我相信值本身在编译时被引用的任何地方都是内联的。这意味着,如果我有const int x = 10;,然后我在整个源代码中使用x 100次,那么这100次对x的引用中的每一次实际上都将在实际编译之前被10所取代。

Const是元数据…
它不是在内存中,而是使用const——告诉编译器"你在const的名称下看到了字面量……"(literal是代码中间的一个数字、字符串或null,就像在for (int i = 0...中,0是literal)。

现在,在大多数情况下-这些字面量…从现在开始——我们讨论的是字面量)是值类型…单例和值类型有什么关系?没有什么……值类型的数据从一个位置复制到另一个位置。所以它不能是单例的

null s呢?null是一个引用的可能值,它表示"我没有引用任何东西"-所以再次…Singleton在这里是不相关的(对于可空值类型- null就像默认构造函数…它们是值类型。这就像情形1)

那么字符串字面值呢?(例如:代码中间的"hello world")这是一个特例。

每个字符串字面值都缓存在一个实习表中…所以-每次你使用相同的字符串字面量-你实际上是在内存中引用相同的对象。但这并不意味着每个具有相同值的字符串都是相同的对象:

string ab = "ab";  
string anotherAB = "ab";  
string another = 'a'.ToString() + 'b'.ToString();    
Console.WriteLine(object.ReferenceEquals(ab, anotherAB)); // true
Console.WriteLine(object.ReferenceEquals(ab, "ab")); // true
Console.WriteLine(object.ReferenceEquals(ab, another)); // false
Console.WriteLine(object.ReferenceEquals("ab", another)); // false