关于c#的const, static, readyonly关键字修饰成员变量时的区别,下面通过一个简单的例子来说明:
1 //SomeType.cs 2 3 using System; 4 5 public sealed class SomeType 6 { 7 public Int32 Id = 1; 8 9 public const Int32 constId = 100; //IL .field public static literal int32 constId = int32(0x00000032) 10 11 public static Int32 staticId = 1000; //IL .field public static int32 staticId 12 13 public readonly Int32 readonlyId = 2000; //IL .field public initonly int32 readonlyId 14 15 public readonly Int32[] readonlyArrayId = new Int32[]{1, 2, 3};//readonlyArrayId本身不能再次write, 但是指向的对象可以改变 16 17 public static readonly Int32 staticReadOnlyId = 5000; //IL .field public static initonly int32 staticReadOnlyId 18 19 public SomeType() 20 { 21 readonlyId = 20001; 22 } 23 }
1 //TestSomeType.cs 2 3 using System; 4 5 public class TestConst 6 { 7 public static void Main(String[] args) 8 { 9 SomeType someType = new SomeType(); 10 11 //test1 12 int result = someType.Id + SomeType.constId + SomeType.staticId + someType.readonlyId + SomeType.staticReadOnlyId; 13 14 //test2 15 someType.readonlyArrayId[1] = 4; 16 17 Console.WriteLine(someType.readonlyArrayId[1]);//output 4 18 19 //test3 20 Console.WriteLine("constId: " + SomeType.constId);// 21 22 Console.WriteLine("staticId: " + SomeType.staticId); 23 } 24 }
一. 结论
1. readonly
(1) 修饰成员变量的时候,该变量只能通过变量定义时或者早构造方法里面赋值。
(2) 修饰的成员变量是实例字段,内存是在构造函数类型的实例时分配的。
(3) 修饰的成员变量是引用类型的时候,不可改变的是引用,引用指向的对象是可以改变的。
2. static
(1) 修饰的成员变量是类型资源,内存是在类型对象中分配的,和具体的实例无关。
3. const
(1) 编译成IL代码后由static literal 修饰,由此可见const修饰的变量最终表示成static类型同时被literal修饰( literal修饰的变量必须在变量声明的时候赋值,编译器编译成IL代码时会直接把这个变量的值插入到引用这个变量的位置替代之前的变量,从而程序在运行时不需要再为此变量分配内存)。
二. const与static的区别
1. 编译SomeType.cs 和 TestSomeType.cs
//生成SomeType.netmodule csc /t:module SomeType.cs //生成TestSomeType.exe csc TestSomeType.cs /addmodule:SomeType.netmodule
运行TestSomeType.exe 可以看到test3中的输出为:
constId: 100 staticId: 1000
现在改变SomeType.cs类型的constId和staticId的值分别为50, 500,然后重新生成SomeType.netmodule
接着再次运行TestSomeType.exe可以看到test3中输出为:
constId: 100 staticId: 500
结果发现只有staticId的值引用的新值。再来看看TestSomeType.cs类的Main函数的IL代码:
可以看到上图的四个标记。标记(1)和(3)是constId编译成IL代码的表示,标记(2)和(4)是staticId编译成IL代码的表示。
对于constId 我们可以发现constId其实已经替换成其对应的值了,所以改变SomeType.cs的constId重新编译影响不到已经编译好的TestSomeType程序集。
对于staticId变量标明的是所在模块的信息,当程序运行起来时CLR会加载其对应的netmodule来获取staticId的值。所以改变SomaeType.cs的staticId的值并重新编译,在TestSomeType程序集中即可获取最新的值。