《CLR via C#》读书笔记(4) -- const与readonly的区别

个人认为两者都可以认为是常量,但是却又是有区别的。

 

首先看看两者所支持的类型:

const 只支持基元类型(所谓基元类型是指编译器直接支持的类型,也就是像int,char,string等等在C#编译器中定义了关键字的类型)。

readonly 可以支持所有类型。

 

然后再看看两者所限定常量的本质:

const 限定的是变量的引用以及变量所代表的值。

readonly仅仅限定的是变量的引用。(如果是引用类型的话,变量所代表的值是能够改变的)

 

最后看看编译器对这两者进行的处理:

const

当编译器遇到一个对const对象的引用时,编译器会将const变量所代表的值直接嵌入生成的IL代码中,也就是说编译完后这段代码和所引用的const变量就没有任何关系了。

这样的话如果我们在代码中修改了const变量的值然后只编译const变量所在程序集的话是不行的,必须为所有引用该变量的代码重新生成IL。

 

readonly

对于readonly的处理,编译器和对待其它的变量一样。因此编译后,调用代码对readonly的变量仍然是存在依赖的。在运行时,调用代码才会去访问readonly

变量所代表的对象的值。

 

写个小程序,生成IL验证一下:

 

public class Constants
{
        public const string ConstName = "Jensen";

        public static readonly int guard = 2;
}



class Program
{
        static void Main(string[] args)
        {
            Console.WriteLine(Constants.ConstName);
            Console.WriteLine(Constants.guard);
            Console.ReadKey();
        }
}


让我们来瞅瞅生成的IL代码:

 

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       30 (0x1e)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "Jensen"  --由于此处是对const变量的引用,编译器直接将它的值写入了IL代码中。
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  ldsfld     int32 [Entity]Entity.Constants::guard --此处是对readonly变量的引用,编译依然是保存了对guard变量运行时的依赖。
  IL_0011:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0016:  nop
  IL_0017:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_001c:  pop
  IL_001d:  ret
} // end of method Program::Main

 

 

posted @ 2012-11-30 15:35  self.refactoring  阅读(197)  评论(0编辑  收藏  举报