C#语言中有两种类型的常量:编译期常量和运行时常量。应该尽量使用运行时常量,而不是编译期常量。虽然编译期常量略快一些,但是没有运行时常量那么灵活。应仅仅在那些性能异常敏感,且常量的值在各个版本之间绝对不会变化时,才使用编译器常量。
运行时常量使用readonly关键字声明,编译时常量使用const关键字声明:
1 //编译时常量,可以声明在方法中 2 public const int Millennium = 2000; 3 //运行时常量,不能声明在方法中 4 public static readonly int ThisYear = 2012;
运行时常量(readonly)和编译时常量(const)的不同
二者的不同之处在于对它们的访问方式不同。编译时常量的值是在在目标代码中进行替换的,以下两个构造生产的IL代码时一样的:
if(myDateTime.Year == Millennium)
if(myDateTime.Year == 2000)
这也就导致了编译期常量仅能用于基本类型(内建的整数和浮点类型)、枚举或字符串。在编译后得到的IL代码中,只有这些常量可以直接被替换成为它们的字面值。
而运行时常量将在运行时求值,在构造函数执行后不能被再次修改。引用运行时常量生成的IL将引用到readonly的变量,而不是变量本身的值(灵活)。
二者的区别在于:readonly的值将在运行时给出,这会带来更好的灵活性。例如,运行时常量可以为任意类型。readonly字段必须在构造函数或初始化器中初始化,而 const 字段只能在该字段的声明中初始化。
我们可以做一个假设:在一个名为Customer的程序集中分别定义了一个const字段和readonly字段:
1 class Customer 2 { 3 public static readonly int StartValue = 5; 4 public const int EndValue = 10; 5 }
在另一个程序集中引用了这两个值,当我们过了一段时间需要更新Customer程序集的这两个字段将值更改:
1 class Customer 2 { 3 public static readonly int StartValue = 15; 4 public const int EndValue = 20; 5 }
随后,分发Customer程序集,而没有重新编译整个应用程序时,我们可以发现在并没有重写编译整个应用程序的情况下所以引用了readonly字段的值变成了我们更新的值,而其他引用了const字段的值却没有更新。
这是因为:
编译器第一次编译应用程序的时候:将所有引用了const字段的变量的值替换成了它对应的常量值(5);对应所有引用readonly字段的变量来说引用的是这个声明为readonly的字段,而不是其字面值。
所以说若想修改所有使用readonly的客户代码的行为,只需要简单的更新一下这个声明了readonly字段的程序集就可以了。而想要更新所有使用const的客户代码的行为则需要重新编译整个应用程序。
小结:
只有在编译期必须获得确定数值时一定要使用const。例如特性(attribute)的参数和枚举的定义等,还有那些在各个版本发布之间不会变化的值。在除此之外的所以情况下,都应该经理选择更加灵活的readonly常量。
阅读书目:《Effective C#》