【问题标题】:How are C# const members allocated in memory? [duplicate]C# const 成员是如何在内存中分配的? [复制]
【发布时间】:2014-06-25 03:02:07
【问题描述】:

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

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

【问题讨论】:

  • const 暗示static
  • @clcto 您能否提供该声明的参考资料?
  • @agarwaen:试试这个; static const int foo = 1;
  • @EdS。编译器说不能将常量“foo”标记为静态
  • “常量或类型声明隐含地是静态成员。”来自MSDN,就在第一个示例代码sn-p之后。

标签: c# memory-management constants


【解决方案1】:

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

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

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

【讨论】:

  • 这很明显,因为 C# 调试器不允许在 const 分配处设置断点 - 即它们“不存在”。
【解决方案2】:

常量通常是可以评估编译时间的东西,编译器很可能会用评估值替换它。

还有Const 表示static(见下面的链接)

常量表达式是可以在 编译时间。因此,常数的唯一可能值 引用类型为 string 和 null。

来源:

C# static and const variables memory

Memory allocation for const in C#

C# do const fields use less memory?

【讨论】:

  • 谢谢。我寻找了第二个链接,但从未找到。
【解决方案3】:

const 表示static,因此每个类只有一个实例。

编辑:添加Reference

【讨论】:

  • 有必要这么多吗?不能在类之间共享 const 吗?想想const string xyz="xyz"; - 编译时实习将会发生。
  • 我查看了C# const reference
  • @ClickRick:现在您谈论的是字符串实习和编译器优化,而不是语义。
  • @agarwaen 在static reference 中很好,我现在已将您链接到 3 次,它声明“常量或类型声明隐含地是静态成员。”
  • 常量定义是静态的,但对常量本身的引用实际上是用常量的值编译的。当常量发生变化时,这会对兼容性产生有趣的影响。
【解决方案4】:

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

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

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

如果您想解决这个问题,最好使用返回常量的公共属性。有关详细信息,请参阅this question 的答案。

我用 .NET Reflector 确认了上述行为。

【讨论】:

  • 这很明显,因为 C# 调试器不允许在 const 分配处设置断点 - 即它们“不存在”。 :-)
【解决方案5】:

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

【讨论】:

    【解决方案6】:

    常量是元数据...
    它不在内存中,而是使用 const - 告诉编译器“您在该 const 的名称下看到文字......把它放在这里”(文字是代码中间的数字、字符串或 null ,就像在for (int i = 0...0 是字面的)。

    现在,在大多数情况下 - 这些(文字......从现在开始 - 我们正在谈论文字)是值类型......单例与值类型有什么关系?!什么都没有... 值类型的数据从一个位置复制到另一个位置。所以它不能是单例。

    nulls 呢? null 是一个可能的引用值,它表示“我没有引用任何内容” - 再说一遍......单例在这里无关紧要(对于可空值类型 - 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
    

    【讨论】:

      猜你喜欢
      • 2012-05-14
      • 1970-01-01
      • 1970-01-01
      • 2017-03-22
      • 2021-07-21
      • 1970-01-01
      • 2012-07-21
      • 2016-03-04
      • 2023-04-06
      相关资源
      最近更新 更多