《Effective C#》读书笔记——条目2:用运行时常量而不是编译期常量<C#语言习惯>

  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#》

posted @ 2012-08-21 12:43  gyzhao  阅读(719)  评论(0编辑  收藏