即:经过编译器编译后

时间:2021-12-24 08:58:04

什么是静态常量(Const)和动态常量(Readonly)

  先解释下什么是静态常量(Const)以及什么是动态常量(Readonly)。
  静态常量(Const)是指编译器在编译时候会对常量进行解析,并将常量的值替换成初始化的阿谁值。
  动态常量(Readonly)的值则是在运行的那一刻才获得的,编译器编译期间将其标示为只读常量,而不用常量的值取代,这样动态常量不必在声明的时候就初始化,而可以延迟到结构函数中初始化。

静态常量(Const)和动态常量(Readonly)之间的区别  

静态常量(Compile-time Constant)

 

动态常量(Runtime Constant)

 

界说

 

声明的同时要设置常量值。

 

声明的时候可以不需要进行设置常量值,可以在类的结构函数中进行设置。

 

类型限制

 

只能修饰基元类型,枚举类型或者字符串类型。

 

没有限制,可以用它界说任何类型的常量。

 

对付类东西而言

 

对付所有类的东西而言,常量的值是一样的。

 

对付类的差别东西而言,常量的值可以是不一样的。

 

内存消耗

 

无。

 

要分配内存,生存常量实体。

 

综述

 

性能要略高,无内存开销,但是限制颇多,不灵活。

 

灵活,便利,但是性能略低,且有内存开销。

 

Const修饰的常量在声明的时候必需初始化;Readonly修饰的常量则可以延迟到结构函数初始化 。

Const常量既可以声明在类中也可以在函数体内,但是Static Readonly常量只能声明在类中。Const是静态常量,所以它自己就是Static的,因此不能手动再为Const增加一个Static修饰符。

Const修饰的常量在编译期间就被解析,即:颠末编译器编译后,我们都在代码中引用Const变量的处所会用Const变量所对应的实际值来取代; Readonly修饰的常量则延迟到运行的时候。

  举个例子来说明一下:

public static readonly int NumberA = NumberB * 10; public static readonly int NumberB = 10; public const int NumberC = NumberD*10; public const int NumberD = 10; static void Main(string[] args) { Console.WriteLine("NumberA is {0}, NumberB is {1}.", NumberA, NumberB);//NumberA is 0, NumberB is 10. Console.WriteLine("NumberC is {0}, NumberD is {1}.", NumberC, NumberD);//NumberC is 100, NumberD is 10. Console.ReadKey(); }

  以上是语法方面的应用,那在实际的用法上,还是有些微妙的变革,凡是不易觉察.
  举个例子来说明一下:
  在措施集DoTestConst.dll 中有一个类MyClass,界说了一个果然的静态变量Count

public static class MyClass { public const int Count = 10; }

  然后此外一个应用措施中引用DoTestConst.dll,并在代码中作如下挪用:

public static void Main(string[] args) { Console.WriteLine(DoTestConst.MyClass.Count);//输出10 Console.ReadKey(); }

  毫无疑问,非常简单的代码,直接输出10。
  接下来更新MyClass的Count的值为20,然后从头编译DoTestConst.dll,并更新到应用措施的地址目录中,注意不要编译应用措施。那么这时候的输出功效按预期那么想应该是20才对,但实际上还是10,为什么呢?
  这就是Const的出格之处,有多出格还是直接看生成的IL,检察IL代码(假设这时候Count的值为10)

  IL_0000: nop
  IL_0001: ldc.i4.s 10
  IL_0003: call void [mscorlib]System.Console::WriteLine(int32)

  红色代码很明显的表白了,直接加载10,没有通过任何类型的加载然后得到对应变量的,也就是说在运行时没有去加载DoTestConst.dll,那么是否意味着没有DoTestConst.dll也可以运行呢?答案是必定的,删除DoTestConst.dll也可以运行,是否很诡异呢?也就解释了之前的尝试,为什么更新Const变量的值之后没有挪用新的值,因为措施在运行的时候根柢不会去加载DoTestConst.dll。那么10这个值是从哪来的呢?实际上CLR对付Const变量做了特殊措置惩罚惩罚,是将Const的值直接嵌入在生成的IL代码中,在执行的时候不会再去从dll加载。这也带来了一个不容易觉察的Bug,因此在引用其他措施集的Const变量时,需考虑到版本更新问题,要解决这个问题就是把挪用的应用措施再编译一次就ok了。但实际措施部署更新时可能只更新个别文件,这时候就必需用Readonly关键字来解决这个问题。

  接下来看Readonly的版本:

public static class MyClass { public static readonly int Count = 10; }

  挪用方代码不乱,接着看生成的IL代码:

  IL_0000: nop
  IL_0001: ldsfld int32 [DoTestConst]DoTestConst.MyClass::Count
  IL_0006: call void [mscorlib]System.Console::WriteLine(int32)