.NET const影响编译的程序集大小

时间:2013-04-06 09:46:28

标签: .net compilation const

为什么在编译时将const用法替换为它们的值,但仍然包含在程序集中?至少这是IL DASM和Reflector所展示的。

目前我正在使用const来定义许多幻数和字符串,以便更容易地更改代码而不会影响运行时性能。

现在我知道这不会影响已用内存,但它仍会影响编译的程序集大小,这对于手机应用程序来说至关重要。

另一个缺点是,在查看反汇编代码时,其他人更容易理解幻数。

我真的很感兴趣为什么编译器(Mono和.NET)确实这样做了?

2 个答案:

答案 0 :(得分:6)

此行为在ECMA-335 standard中指定(其中.NET和Mono都是实现)。引用第II.22.9节“常数”:

  

请注意,Constant信息不会直接影响运行时行为,尽管它通过Reflection可见(因此可用于实现System.Enum.ToString提供的功能)。编译器在编译时在导入元数据时检查此信息,但常量本身的值(如果使用)将嵌入到编译器发出的CIL流中。在运行时没有CIL指令可以访问Constant表。

也就是说,const值是“内联的”(可能是因为它们可能是出于性能原因),但仍保留在元数据中,因此编译器和工具可以对它们进行检查。

如果没有为const - 字段发出元数据,这将产生这些后果(可能还有其他 - 这只是两个例子):

  • 像Reflector这样的编译器或工具无法再区分常规字段和const字段。
  • 如果您使用System.Reflection检查某个字段,则无法再使用FieldInfo.IsLiteral property

答案 1 :(得分:2)

增加的程序集大小基本上是由于C#编译器发出了关于const的其他元数据。


您对此短节目的期望是什么?

class Program
{
    public const int C = 0;
    public       int F = 0;

    static void Main(string[] args)
    {
        foreach (FieldInfo field in typeof(Program).GetFields())
        {
            Console.WriteLine("{0}: IsLiteral = {1}", field.Name, field.IsLiteral);
        }
    }
}

实际输出是:

C: IsLiteral = True
F: IsLiteral = False

与C#源中的声明完全匹配:两个字段,其中一个const

现在让我们假设C#编译器决定不发出Constant元数据。然后输出将是:

C: IsLiteral = False
F: IsLiteral = False

与C#源代码相比,这显然是不正确的,因为现在这两个字段都显示为非const

最后,假设C#编译器决定不发布C的任何元数据(因为它“无论如何”内联“了字段的值):

F: IsLiteral = False

这也是不正确的,因为反射不再报告存在C#源代码中明显存在的字段。至少对我来说,这将是一个令人兴奋的好时刻。

这些反例应该明确为什么即使对于const字段也会发出完整的元数据也是一件好事。

相关问题