常量的定义

 常量是在编译时设置其值并且永远不能更改其值的字段。 使用常量可以为特殊值提供有意义的名称,而不是数字文本(“幻数”)。-————————​​MSCN​

若要定义整型类型(​​int​​、​​byte​​ 等)的常量值,请使用枚举类型。 有关详细信息,请参阅​​枚举​​。

若要定义非整型常量,一种方法是将它们分组到一个名为 ​​Constants​​ 的静态类。 这要求对常量的所有引用都在其前面加上该类名,如下例所示。

常量和只读字段的区别

1、定义的作用关键字不一样
常量
:枚举、const 定义的字段。一编译就不能更改了,不允许有表达式。

只读字段:readonly定义的字段,是变量,可以由表达式构成。

 

2、值的确定的位置不一样:

Compile-time constant:编译时常量 ,编译时确定的值

Runtime constant:运行时常量,只有在运行时CLR中才能确定的值

常量式在编译时就确定值了。

只读字段在运行时才确定值:动态常量

 

枚举、const、readonly  IL代码的比较

声明变量



public readonly int SOU = 12;
public const int seiu = 12;
enum n { i=0}


IL代码



.field public initonly int32 SOU
.field public static literal int32 seiu = int32(12)
.field public static literal valuetype Galaxy.Program/n i = int32(0)//枚举中字段是IL代码和Const 常量定义的代码是一样的完整枚举IL代码如下:
.class nested private auto ansi sealed n
extends [System.Runtime]System.Enum
{
// Fields
.field public specialname rtspecialname int32 value__
.field public static literal valuetype Galaxy.Program/n i = int32(0)//枚举中字段是IL代码和Const 常量定义的代码是一样的

} // end of class n


通过IL对比可以看出CLR 用literal定义编译器常量,literal 这个单词的本意就是“字面上,符号“。用initonly 定义只读字段

literal为字面字段,定义时必须初始化,不能被修改,是编译时常量且只能用于值类、引用类和接口类;

initonly 仅在构造函数进行初始化,可赋值多次,静态只读字段只能在静态构造函数中初始化。

当某个字段是引用类型,并且该字段标记为readonly时,那么不可改变的是引用,而非字段引用的值

C# 常量(const)和自读字段(static和readonly)在实际编程差别

下面声明:



public static readonly int A = 2; //A为运行时常量
public const int B = 3; //B为编译时常量


下面的表达式:



int C = A + B;


经过编译后与下面的形式等价:



int C = A + 3;


可以看到,其中的const常量B被替换成字面量3,而readonly字段A则保持引用方式。

声明及初始化

readonly字段只能声明为类字段,支持实例类型或静态类型,可以在声明的同时初始化或者在构造函数中进行初始化,初始化完成后便无法更改。

const常量除了可以声明为类字段之外,还可以声明为方法中的局部常量,默认为静态类型(无需用static修饰,否则将导致编译错误),但必须在声明的同时完成初始化。

数据类型支持

由于const常量在编译时将被替换为字面量,使得其取值类型受到了一定限制。const常量只能被赋予数字(整数、浮点数)、字符串以及枚举类型。下面的代码无法通过编译:



public const DateTime D = DateTime.MinValue;


改成readonly就可以正常编译:



1 public readonly DateTime D = DateTime.MinValue;


可维护性

readonly以引用方式进行工作,某个常量更新后,所有引用该常量的地方均能得到更新后的值。

const的情况要稍稍复杂些,特别是跨程序集调用:



C#细说 常量_字面量

1 public class Class1
2 {
3 public static readonly int A = 2; //A为运行时常量
4 public const int B = 3; //B为编译时常量
5 }
6
7 public class Class2
8 {
9 public static int C = Class1.A + Class1.B; //变量C的值为A、B之和
10 }
11
12 Console.WriteLine(Class2.C); //输出"5"


C#细说 常量_字面量


 

假设Class1与Class2位于两个不同的程序集,现在更改Class1中的常量值:



1 public class Class1
2 {
3 public static readonly int A = 4; //A为运行时常量
4 public const int B = 5; //B为编译时常量
5 }


编译Class1并部署(注意:这时并没有重新编译Class2),再次查看变量C的值:



1 Console.WriteLine(Class2.C); //输出"7"


结果可能有点出乎意料,让我们来仔细观察变量C的赋值表达式:



public static int C = Class1.A + Class1.B;


编译后与下面的形式等价:



public static int C = Class1.A + 3;


因此不管常量B的值如何变,对最终结果都不会产生影响。虽说重新编译Class2即可解决这个问题,但至少让我们看到了const可能带来的维护问题。

性能比较

const直接以字面量形式参与运算,性能要略高于readonly,但对于一般应用而言,这种性能上的差别可以说是微乎其微。

适用场景

在下面两种情况下:

a.取值永久不变(比如圆周率、一天包含的小时数、地球的半径等)

b.对程序性能要求非常苛刻

可以使用const常量,除此之外的其他情况都应该优先采用readonly常量。