【问题标题】:How to stop C# from replacing const variable with their values?如何阻止 C# 用它们的值替换 const 变量?
【发布时间】:2014-01-28 03:43:01
【问题描述】:

我们有一个项目被编译成一个名为 consts.dll 的 DLL,其中包含以下内容:

public static class Consts
{
    public const string a = "a";
    public const string b = "b";
    public const string c = "c";
}

我们有多个此类项目,每个项目都编译成同名的 DLL (consts.dll),我们根据需要替换它们。 我们还有另一个使用这些常量的类:

public class ConstsUser 
{
    string f() { return Consts.a; }
}

不幸的是,Consts.a 被优化为 "a" ,所以即使我们替换 Consts.dll 实现,我们仍然得到 "a" 而不是正确的值,我们需要重新编译 ConstsUser。有没有办法阻止优化器用它们的值替换 const 变量?

【问题讨论】:

  • 请注意,进行此替换的不是优化器,这只是 C# 编译器在所有实例中的行为
  • 类的每个公共成员,包括常量,都是该类接口的一部分。常量是特殊的,因为不仅它们的名称,而且它们的值也是接口的一部分。当你改变一个类的接口时,你必须重新编译它的所有依赖代码。更改公共const 成员的值是一项重大更改。您不能换掉 DLL,并期望一切都能正常工作,原因与您期望更改类名或其中一个成员的参数类型会触发错误的原因相同。
  • 也许你的常数毕竟不是那么常数?说真的,仅将 const 用于实际恒定的事物。 Pi 就是一个很好的例子。
  • 如果您的常量不是常量,请不要使用 const... 实际上,它们的值甚至可能不在代码中;它们应该在配置文件中。

标签: c# optimization


【解决方案1】:

我认为static readonly 修饰符的使用符合您的需求:

public static class Consts
{
    public static readonly string a = "a";
    public static readonly string b = "b";
    public static readonly string c = "c";
}

常量在调用站点上是硬编码的,所以这是你的问题。静态只读变量只能在Consts类的变量声明或静态构造函数中修改,不会在调用点内联。

【讨论】:

  • 可选参数也是如此。
【解决方案2】:

来自书CLR via c#

当代码引用一个常量符号时,编译器会在 定义常量的程序集的元数据,提取 常量的值,并将该值嵌入到发出的中间体中 语言 (IL) 代码。因为常量的值直接嵌入 代码,常量不需要为它们分配任何内存 运行时。另外,你不能得到一个常量的地址,你 不能通过引用传递常量。这些限制也意味着 常量没有一个好的跨汇编版本控制故事,所以你 只有在您知道符号的值将 永不改变

正如我们所见,当我们知道符号的值永远不会改变时,使用const 确实有其好处。它可以更快地执行,因为 CLR 不需要解析值。

实际上,在构建应用程序程序集之后,DLL 程序集 甚至在运行时都没有加载,并且可以从磁盘中删除,因为 编译器甚至不添加对 DLL 程序集的引用 应用程序的元数据。

正如@Sergey Berezovskiy 已经建议的那样,如果您需要 CLR 在运行时动态解析值,我们可以使用static readonly。此解决方案会影响性能,但还有另一个好处。

此外,字段可以是任何数据类型,因此您不必 将自己限制在编译器的内置原始类型(当您 做常量)。

【讨论】:

    猜你喜欢
    • 2013-01-26
    • 2023-03-22
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    相关资源
    最近更新 更多