我们有一个项目被编译成一个名为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),我们会根据需要替换它们。 我们有另一个使用这些consts的类:
public class ConstsUser
{
string f() { return Consts.a; }
}
不幸的是,Consts.a
已经优化为“a”,所以即使我们替换Consts.dll实现,我们仍然会得到“a”而不是正确的值,我们需要重新编译ConstsUser
。反正有没有阻止优化器用它们的值替换const变量?
答案 0 :(得分:117)
我认为使用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
类的变量声明或静态构造函数中修改,并且不会在调用站点上内联。
答案 1 :(得分:36)
当代码引用常量符号时,编译器会在中查找符号 定义常量的程序集的元数据,提取 常量值,将值嵌入发出的中间值中 语言(IL)代码。因为常量值直接嵌入 代码,常量不需要为它们分配任何内存 运行即可。另外,你不能得到一个常数的地址和你 不能通过引用传递常量。这些限制也意味着 常量没有一个好的跨程序集版本故事,所以你 只有在您知道符号的值时才会使用它们 永不改变。
正如我们所看到的,当我们知道符号的值永远不会改变时,使用const
确实有其好处。它可以执行得更快,因为CLR不需要解析该值。
实际上,在构建应用程序集后,DLL程序集 甚至没有在运行时加载,可以从磁盘中删除,因为 编译器甚至没有添加对DLL程序集的引用 应用程序的元数据。
正如@Sergey Berezovskiy已经建议的那样,如果您需要CLR在运行时动态解析值,我们可以使用static readonly
。此解决方案会影响性能,但还有另一个好处。
此外,字段可以是任何数据类型,因此您不必这样做 限制你自己编译器的内置基元类型(和你一样) 做常数)。