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

时间:2014-01-09 14:21:09

标签: 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),我们会根据需要替换它们。 我们有另一个使用这些consts的类:

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

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

2 个答案:

答案 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)

从书CLR via c#

  

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

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

  

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

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

  

此外,字段可以是任何数据类型,因此您不必这样做   限制你自己编译器的内置基元类型(和你一样)   做常数)。