C# const和readonly区别,代码示例

工作中看公司项目,大量用到const,这里复习一下

   先解释下什么是静态常量(Const)以及什么是动态常量(Readonly)。
  静态常量(Const)是指编译器在编译时候会对常量进行解析,并将常量的值替换成初始化的那个值。
    即运行时,已经确定了所有的值,即没有运行,里面已经有值
  动态常量(Readonly)的值则是在运行的那一刻才获得的,编译器编译期间将其标示为只读常量,而不用常量的值代替,
    这里还没有确定,仅仅只是标记只读,到运行时才确定
    这样动态常量不必在声明的时候就初始化,而可以延迟到构造函数中初始化。

     关于const和readonly区别
    const
    声明的同时要设置常量值。 
    只能修饰基元类型,枚举类型或者字符串类型。
    对于所有类的对象而言,常量的值是一样的。
    readonly
    声明的时候可以不需要进行设置常量值,可以在类的构造函数中进行设置。
    没有限制,可以用它定义任何类型的常量。
    对于类的不同对象而言,常量的值可以是不一样的。

  1. Const修饰的常量在声明的时候必须初始化;Readonly修饰的常量则可以延迟到构造函数初始化 。
  2. Const常量既可以声明在类中也可以在函数体内,但是Static Readonly常量只能声明在类中。Const是静态常量,所以它本身就是Static的,因此不能手动再为Const增加一个Static修饰符。
  3. 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

 

你可能感兴趣的:(c#)