CLR via C# 定义常量将导致创建元数据
CLR via C# 定义常量将导致创建元数据
由于常量值从不变化,所以常量总是被视为类型定义的一部分。换言之,常量总是被视为静态成员,而不是实例成员。定义常量将导致创建元数据。
代码引用常量符号时,编译器在定义常量的程序集的元数据中查找该符号,提取常量的值,将值签入生成的 IL 代码中。由于常量的值直接嵌入代码,所以在运行时不需要为常量分配任何内存。除此之外,不能获取常量的地址,也不能以传引用的方式传递常量。这些限制意味着常量不能很好地支持跨程序集的版本控制。因此,只有确定一个符号的值从不变化才应定义常量。(将 MaxInt6
定义为32767
就是一个很好的例子)。下面来演示我刚才所说的内容。首先,请输入以下代码,并将其编译成一个 DLL 程序集。
using System;
pulbic sealed class SomeLibraryType {
// 注意:C# 不允许为常量指定 static 关键字,
// 因为常量总是隐式为 static
public const Int32 MaxEntriesInList = 50;
}
接着用以下代码生成一个应用程序程序集:
用 csc.exe 的
/r
开关来引用刚才的.dll 文件。
using System;
public sealed class Program {
public static void Main() {
Console.WriteLine("Max entries supported in list: " + SomeLibraryType.MaxEntriesInList);
}
}
注意代码引用了在 SomeLibraryType
类中定义的 MaxEntriesInList
常量。编译器生成引用程序代码时,会注意到 MaxEntriesInList
是值为 50
的常量符号,所以会将 Int32
值 50
嵌入应用程序的 IL 代码,如下所示。事实上
,在生成了应用程序程序集之后,运行时根本不会加载 DLL 程序集,可以把它从磁盘上删除。
.method public hidebysig static void Main() cil managed
{
entrypoint
// Code size 25 (0x19)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Max entries supported in list: "
IL_0006: ldc.i4.s 50
IL_0008: box [mscorlib]System.Int32
IL_000d: call string [mscorlib]System.String::Concat(object, object)
IL_0012: call void [mscorlib]System.Console::WriteLine(string)
IL_0017: nop
IL_0018: ret
} // end of method Program::Main
这个例子清楚地展示了版本控制问题。如果开发人员将常量 MaxEntriesInList
的值更改为 1000
,并且只是重新生成 DLL 1000
,并且只是重新生成 DLL 程序集,那么应用程序集不受任何影响。应用程序要获得新值,也必须重新编译。如果希望在运行时从一个程序集中提取另一个程序集中的值,那么不应该使用常量,而应该使用 readonly
字段。