const效率高,readonly更灵活
区别:
1、const是一个编译期常量,readonly是一个运行时常量
2、const只能修饰基元类型、枚举类型或字符串类型,readonly没有限制
const天然就是static的,不能手动为const添加一个static修饰符:
static const int ConstValue = 100;//编译错误:常量“ConstValue”不能标记为 static
const效率高是因为经编译后,在代码中引用const变量的地方会用const变量所对应的实际值来代替,如:
1 Console.WriteLine(ConstValue); 2 Console.WriteLine(100);
IL_0000: nop IL_0001: ldc.i4.s 100 IL_0003: call void [mscorlib]System.Console::WriteLine(int32) IL_0008: nop IL_0009: ldc.i4.s 100 IL_000B: call void [mscorlib]System.Console::WriteLine(int32)
第一行代码和第二行代码生成的IL代码时一致的。
readonly变量时运行时变量,其赋值行为发生在运行时,它在第一次赋值后将不可改变:
1)对于值类型变量,值本身不可改变。
2)对于引用类型变量,引用本身(相当于指针)不可改变。
例1:readonly修饰值类型变量
1 static void Main(string[] args) 2 { 3 Student student = new Student(18);//传值18 4 student.age = 20;//编译不通过,无法对只读的字段赋值(构造函数或变量初始值指定项中除外) 5 } 6 7 class Student 8 { 9 public readonly int age; 10 public Student(int value) 11 { 12 age = value;//给只读变量赋值18 13 } 14 }
student实例在构造方法对只读变量age进行赋值,赋值后不可改变,所以第4行代码编译不通过。
例2:readonly修饰引用类型编写
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Sample sample = new Sample(new Student(18)); 6 sample.student.age = 20;//编译通过,允许修改age 7 //sample.student = new Student(20);//编译不通过,无法对只读的字段赋值(构造函数或变量初始值指定项中除外) 8 } 9 } 10 class Sample 11 { 12 public readonly Student student; 13 public Sample(Student value) 14 { 15 student = value; 16 } 17 } 18 class Student 19 { 20 public int age; 21 public Student(int value) 22 { 23 age = value;//给只读变量赋值18 24 } 25 }
因为引用本身不可变,所以第7行代码编译不通过,指向的实例不可变;但是所指的实例的值却是可以改变的,所以第6行代码编译可以通过。
readonly所代表的运行时含义有一个重要的作用,就是可以为每个类的实例指定一个readonly变量。
例3:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Student student = new Student(18); 6 } 7 } 8 class Student 9 { 10 public readonly int age = 0; 11 public Student(int value) 12 { 13 age = value; 14 } 15 }
例3的代码是可以运行的,age首先在初始化时被初始化器赋值为0,然后,student实例化时,在构造方法中又被赋值为18。实际上,应该把初始化器理解成构造方法的一部分,它其实是一个语法糖。在构造方法内,可以多次对readonly赋值。
参考:《编写高质量代码改善C#程序的157个建议》陆敏技