C# readonly和const

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个建议》陆敏技

posted @ 2020-06-18 16:17  XXXUJIA  阅读(959)  评论(0编辑  收藏  举报