目录
什么是静态常量(Const)和动态常量(Readonly) 先解释下什么是静态常量(Const)以及什么是动态常量(Readonly)。 静态常量(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(); } 以上是语法方面的应用,那在实际的用法上,还是有些微妙的变化,通常不易发觉. 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。 IL_0000: nop 红色代码很明显的表明了,直接加载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 很明显加载代码变了,一个很常见的ldsfld动作,请求了DoTestConst.MyClass的Count变量,是通过强制要求加载DoTestConst来实现的。因此这时候更新Count的值重新编译之后,还是不编译调用程序,然后再执行就会看到新的值。而这时候如果删除DoTestConst.dll那么,会出现找不到dll之类的异常。这也充分说明了对于Readonly定义的变量是在运行时加载的。 动态常量(Readonly)被赋值后不可以改变ReadOnly 变量是运行时变量,它在运行时第一次赋值后将不可以改变。其中“不可以改变”分为两层意思:
值类型变量,举个例子说明一下:
public class Student { public readonly int Age;
public Student(int age) { this.Age = age; } }
Student的实例Age在构造函数中被赋值以后就不可以改变,下面的代码不会编译通过: Student student = new Student(20); student.Age = 21; //错误信息:无法对只读的字段赋值(构造函数或变量初始化器中除外) 引用类型变量,举个例子说明一下:
public class Student { public int Age; //注意这里的Age是没有readonly修饰符的
public Student(int age) { this.Age = age; } }
public class School { public readonly Student Student;
public School(Student student) { this.Student = student; } } School实例的Student是一个引用类型的变量,赋值后,变量不能再指向其他任何的Student实例,所以,下面的代码将不会编译通过: School school = new School(new Student(10)); school.Student = new Student(20);//错误信息:无法对只读的字段赋值(构造函数或变量初始化器中除外) 引用本身不可以改变,但是引用说指向的实例的值是可以改变的。所以下面的代码是可以编译通过的: School school = new School(new Student(10)); school.Student.Age = 20; 在构造方法中,我们可以多次对Readonly修饰的常量赋值。举个例子说明一下:
public class Student { public readonly int Age = 20;//注意:初始化器实际上是构造方法的一部分,它其实是一个语法糖
public Student(int age) { this.Age = age; this.Age = 25; this.Age = 30; } }
总结 Const和Readonly的最大区别(除语法外) |
|
来自: ontheroad96j47 > 《待分类》