少年未央

导航

C#: const与readonly的用法和区别解析(转)

总结一下const和readonly:

1.const和readonly的值一旦初始化则都不再可以改写;
2.const只能在声明时初始化;readonly既可以在声明时初始化也可以在构造器中初始化;
3.const隐含static,不可以再写static const;readonly则不默认static,如需要可以写static readonly;
4.const是编译期静态解析的常量(因此其表达式必须在编译时就可以求值);readonly则是运行期动态解析的常量;
5.const既可用来修饰类中的成员,也可修饰函数体内的局部变量;readonly只可以用于修饰类中的成员.

注意,第四点尤为重要,我用以下代码来说明和验证:

1.建立文本文件,然后改成.cs文件-lib.cs:

using System;   
using System.Collections.Generic;   
using System.Linq;   
using System.Text;   
  
namespace ConstReadonly_Base   
{   
    public class Test   
    {   
        public const double PI = 3.14;   
        public static readonly double pi = 3.14;   
    }   
}  

2.在命令行中输入: csc /t:library lib.cs,就会生成一个lib.dll文件.

3.建立文本文件,然后改成.cs文件-demo.cs:

using System;   
using System.Collections.Generic;   
using System.Linq;   
using System.Text;   
  
namespace ConstReadonly_Demo   
{   
    class Program   
    {   
        static void Main(string[] args)   
        {   
            Console.WriteLine(ConstReadonly_Base.Test.PI);   
            Console.WriteLine(ConstReadonly_Base.Test.pi);   
            Console.ReadKey();   
        }   
    }   
}  

4.在命令行中输入: csc /r:lib.dll demo.cs,也就会生成一个demo.exe文件.

双击,结果如下:

3.14

3.14

5.更改lib.cs为:

using System;   
using System.Collections.Generic;   
using System.Linq;   
using System.Text;   
  
namespace ConstReadonly_Base   
{   
    public class Test   
    {   
        public const double PI = 3.1415;   
        public static readonly double pi = 3.1415;   
    }   
}  

6.再次双击demo.exe文件,结果却如下:

3.14

3.1415

(注: 直接双击demo.exe是直接运行,不再编译,上结果也就是运行期结束的结果,相当于跳过了编译)

原因是什么呢?请听我慢慢道来.

用ILDasm工具(这里假定你会用),选择lib.dll,内容如下:

双击PI段:

内容为

field public static literal float64 PI = float64(3.1415000000000002)  

双击pi段:

内容为

field public static initonly float64 pi 

 

明显lib.cs被编译成元数据和IL汇编时,PI直接被替换成float64(3.1415000000000002)

而.cctor: void()静态构造函数中,

 

.method private hidebysig specialname rtspecialname static    
        void  .cctor() cil managed   
{   
  // Code size       15 (0xf)   
  .maxstack  8   
  IL_0000:  ldc.r8     3.1415000000000002   
  IL_0009:  stsfld     float64 ConstReadonly_Base.Test::pi   
  IL_000e:  ret   
} // end of method Test::.cctor  

pi是动态分配内存的,直到运行时才调用静态构造函数来初始化pi.

如果这时你还是不太明白,让我们接下去看:

用ILDasm工具,选择demo.exe,内容如下:

 

我们来看看Main函数中我们到底做了些什么:

.method private hidebysig static void  Main(string[] args) cil managed   
{   
  .entrypoint   
  // Code size       34 (0x22)   
  .maxstack  8   
  IL_0000:  nop   
  IL_0001:  ldc.r8     3.1400000000000001   
  IL_000a:  call       void [mscorlib]System.Console::WriteLine(float64)   
  IL_000f:  nop   
  IL_0010:  ldsfld     float64 ['ConstReadonly-Base']ConstReadonly_Base.Test::pi   
  IL_0015:  call       void [mscorlib]System.Console::WriteLine(float64)   
  IL_001a:  nop   
  IL_001b:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()   
  IL_0020:  pop   
  IL_0021:  ret   
} // end of method Program::Main  


WriteLine()打印PI时, 

 

IL_0001:  ldc.r8     3.1400000000000001   
IL_000a:  call       void [mscorlib]System.Console::WriteLine(float64) 

 

这说明编译时,PI被编译成一个常量.

WriteLine()打印pi时,

 

IL_0010:  ldsfld     float64 ['ConstReadonly-Base']ConstReadonly_Base.Test::pi  

这说明编译时,pi被编译成调用ConstReadonly_Base.Test::pi,可见pi量是动态分配和调用的.

相信大家都明白了吧!

posted on 2010-01-12 23:58  少年未央  阅读(722)  评论(0)    收藏  举报