如何阻止C#用它们的值替换常量变量?

如何阻止C#用它们的值替换常量变量?,c#,optimization,C#,Optimization,我们有一个项目,它被编译成一个名为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 clas

我们有一个项目,它被编译成一个名为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
。是否有任何方法可以阻止优化器用常量变量的值替换常量变量?

我认为使用
静态只读
修饰符符合您的需要:

public static class Consts
{
    public static readonly string a = "a";
    public static readonly string b = "b";
    public static readonly string c = "c";
}
常量在调用站点上是硬编码的,所以这是您的问题。静态只读变量只能在
Consts
类的变量声明或静态构造函数中修改,并且它不会内联在调用站点上。

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

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

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

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

此外,字段可以是任何数据类型,因此您不必这样做 将自己限制为编译器的内置基元类型(如需要) 对于常量,请执行此操作)


请注意,进行替换的不是优化器,而是C#编译器在所有实例中的行为。类的每个公共成员(包括常量)都是该类接口的一部分。常量是特殊的,因为不仅它们的名称,而且它们的值也是接口的一部分。更改类的接口时,必须重新编译其所有依赖代码。更改public
const
成员的值是一个突破性的更改。你不能调出DLL,期望一切都能正常工作,这与你期望更改其成员的类名或参数类型会触发错误的原因是一样的。答案也很有趣:这再一次表明你的常数可能不是那么恒定?说真的,只对实际上是常量的东西使用常量。Pi是一个很好的例子。如果你的常数不是常数,不要使用常数。。。实际上,它们的值甚至不应该出现在代码中;它们应该在配置文件中。对于可选参数也是如此。