工作中看公司项目,大量用到const,这里复习一下
先解释下什么是静态常量(Const)以及什么是动态常量(Readonly)。
静态常量(Const)是指编译器在编译时候会对常量进行解析,并将常量的值替换成初始化的那个值。
即运行时,已经确定了所有的值,即没有运行,里面已经有值
动态常量(Readonly)的值则是在运行的那一刻才获得的,编译器编译期间将其标示为只读常量,而不用常量的值代替,
这里还没有确定,仅仅只是标记只读,到运行时才确定
这样动态常量不必在声明的时候就初始化,而可以延迟到构造函数中初始化。
关于const和readonly区别
const
声明的同时要设置常量值。
只能修饰基元类型,枚举类型或者字符串类型。
对于所有类的对象而言,常量的值是一样的。
readonly
声明的时候可以不需要进行设置常量值,可以在类的构造函数中进行设置。
没有限制,可以用它定义任何类型的常量。
对于类的不同对象而言,常量的值可以是不一样的。
- Const修饰的常量在声明的时候必须初始化;Readonly修饰的常量则可以延迟到构造函数初始化 。
- Const常量既可以声明在类中也可以在函数体内,但是Static Readonly常量只能声明在类中。Const是静态常量,所以它本身就是Static的,因此不能手动再为Const增加一个Static修饰符。
- Const修饰的常量在编译期间就被解析,即:经过编译器编译后,我们都在代码中引用Const变量的地方会用Const变量所对应的实际值来代替; Readonly修饰的常量则延迟到运行的时候。
个人总结,Const一个是常量,相当于给固定值取的别名,所以除了定义时不能赋值,至于readonly则是在可以构造函数,变量初始化器中多次赋值
且Const的变量是嵌入在IL代码中,编译时就加载好,不依赖外部dll(这也是为什么不能在构造方法中赋值)
Const本身就是静态的,所以不能用static修饰
相关代码示例如下:
using DoTestConst;
using System;
namespace TestConstReadonly
{
class Program
{
//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.
/*
* 因为程序在运行的时候根本不会去加载DoTestConst.dll。那么10这个值是从哪来的呢?
* 实际上CLR对于Const变量做了特殊处理,是将Const的值直接嵌入在生成的IL代码中,在执行的时候不会再去从dll加载。
* 这也带来了一个不容易发觉的Bug,因此在引用其他程序集的Const变量时,需考虑到版本更新问题,要解决这个问题就是把调用的应用程序再编译一次就ok了。
* 但实际程序部署更新时可能只更新个别文件,这时候就必须用Readonly关键字来解决这个问题。
*/
//赋值号左边必须为变量,属性,索引器,即常量不是变量,有点类似枚举,它就是一个固定值的别名
//DoTestConst.MyClass.Count = 20;
//DoTestConst.MyClass1.Count = 20;
Console.WriteLine(DoTestConst.MyClass.Count);
Console.WriteLine(DoTestConst.MyClass1.Count);
//同样的操作,编译类库将生成的dll文件,替换当前项目的引用目录
//一个readonly跟着类库变化,
//一个const相当于缓存,直接在il中间代码中,指没有变化,无需加载dll获取对应的值
//new Class1().TestRel();
//Student student = new Student(20);
//student.Age = 21; //错误信息:无法对只读的字段赋值(构造函数或变量初始化器中除外)
//School school = new School(new Student(10));
//school.Student = new Student(20);//错误信息:无法对只读的字段赋值(构造函数或变量初始化器中除外)
School school = new School(new Student(10));
school.Student.Age = 20;
Console.ReadKey();
}
}
}
另一个类库代码示例
using System;
namespace DoTestConst
{
//public class Class1
//{
// public void TestRel() {
// Console.WriteLine("test rel compile 1");
// }
//}
public static class MyClass
{
public const int Count = 60;
}
public static class MyClass1
{
public static readonly int Count = 20;
}
//public class Student
//{
// public readonly int Age;
// public Student(int age)
// {
// this.Age = age;
// }
//}
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;
}
}
public class Student2
{
public readonly int Age = 20;//注意:初始化器实际上是构造方法的一部分,它其实是一个语法糖
public Student2(int age)
{
this.Age = age;
this.Age = 25;
this.Age = 30;
}
}
}
万丈高楼平地起,也是建立在牢固的基础之上,花时间将知识全面,系统的整理,现在的深度,广度,决定未来的高度
主要参考如下:https://www.cnblogs.com/daidaibao/p/4214268.html