对于常量,C#里有两个不同的版本:运行时常量和编译时常量。

关键字readonly来声明(declare)一个运行时常量,编译时常量是用关键字const声明的

//编译时常量

public cocnst int _Millennium = 2000;
//运行时常量

public static readonly int _ThisYear = 2009;

二者区别如下:

  1. 访问不同

    一个编译时常量会被目标代码中的值直接取代。下面的代码:
    if(myDateTime.Year == _Millennium)
    会与下面写的代码编译成完全相同的IL代

    if(myDateTime.Year == 2000)

    运行时常量的值是在运行时确定的。当你引用一个只读常量时(read-only)IL会为你引用一个运行时常量的变量,而不是直接使用该值。

  2. 数据类型不同

编译时常量只能是基本类型,枚举或者是字符串

//编译失败, 用 readonly 替代则能通过编译:

private const DateTime _classCreation = new DateTime(2000,1,1,0,0,0);

运行时常量可以是任何类型的数据,可以在构造函数里对他们初始化,赋值

只读数据最重要的区别是他们在运行时才确定值。当你使用只读变量时,IL会为你产生一个对只读变量引用,而不是直接产生数值。随着时间的推移,这个区别在(系统)维护上有深远的潜在影响。
编译时常量生成的IL代码就跟直接使用数值时生成的IL是一样的,即使是在跨程序集时:一个程序集里的编译时常量在另一个程序集会保留着同样的值

假设你已经在程序集Infrastructure中同时定义了一个const和一个readonly变量:
public class UserfulValues{
public static readonly int StartValue = 5;
public const int EndValue = 10;
}
同时,在另一个程序集中,你引用了这些值:
for(int i=UserfulValues.StartValue;i<UserfulValues.EndValue;i++){
Console.WriteLine("value is {0}",i);
}
如果你运行这个简单测试程序,你可以看到下面明显的结果:
value is 5
value is 6
...
value is 9
过后,你又为程序集Infrastructure发布了个新的版本,并做了如下的修改:
public class UserfulValues{
public static readonly int StartValue = 105;
public const int EndValue = 120;
}
你单独的发布了程序集Infrastructure而没有全部编译你的程序,你希望得到下面的:
value is 105
value is 106
...
value is 119
事实上,你什么也得不到。上面的循环已经是用105开始而用10来结束。C#编译器(在编译时)把常量用10来代替应用程序的程序集中的使用,而不是用常量EndValue所存储的值。而常量StartValue的值,它是被申明为只读的,它可以在运行时重新读取该常量的值。因此,应用程序的程序集可以在不用重新编译的情况下使用新的数据,简单的编译一下Infrastructure程序集,然后重新布署安装一下,就足够让你的客户可能使用这些新的数据了。更新的编译时常量应该看成是接口的变化。你必须重新编译所有引用到编译时常量的代码。更新的运行时常量则可以当成是实现的改变,这于在客户端已经存在的二进制代码是兼容的

综上所述个人认为即使是编译常量(const)性能更搞,但为了更好的申缩扩张尽量的时候运行时常量(readonly)