const与readonly 很像,都是将变量声明为只读,且在变量初始化后就不可改写。那么,const与readonly 这两个修饰符到底区别在什么地方呢?其实,这个牵扯出C#语言中两种不同的常量类型:静态常量(compile-time constants)和动态常量(runtime constants)。这两者具有不同的特性,错误的使用不仅会损失效率,而且还会造成错误。
首先先解释下什么是静态常量以及什么是动态常量。静态常量是指编译器在编译时候会对常量进行解析,并将常量的值替换成初始化的那个值。而动态常量的值则是在运行的那一刻才获得的,编译器编译期间将其标示为只读常量,而不用常量的值代替,这样动态常量不必在声明的时候就初始化,而可以延迟到构造函数中初始化。
当你大致了解上面的两个概念的时候,那么就可以来说明const与readonly了。const修饰的常量是上述中的第一种,即静态常量;而readonly则是第二种,即动态常量。那么区别可以通过静态常量与动态常量的特性来说明:
1)const修饰的常量在声明的时候必须初始化;readonly修饰的常量则可以延迟到构造函数初始化
2)const修饰的常量在编译期间就被解析,即常量值被替换成初始化的值;readonly修饰的常量则延迟到运行的时候
此外const常量既可以声明在类中也可以在函数体内,但是static readonly常量只能声明在类中。
-
<span style="font-size:18px;">class Program
-
{
-
class Test
-
{
-
public const int constTest = 2;
-
public readonly int readonlyTest;
-
//也可以在声明时初始化
-
//public readonly int readonlyTest=3;
-
public static readonly int staticReadonlyTest;
-
//同readonlyTest
-
public Test()
-
{
-
readonlyTest = 3;
-
//延迟到构造函数中初始化
-
}
-
static Test()
-
{
-
staticReadonlyTest = 4;
-
//延迟到构造函数中初始化
-
//注意:static变量在static构造函数中初始化
-
}
-
}
-
static void Main(string[] args)
-
{
-
Console.WriteLine("constTest is {0},staticReadonlyTest is {1}", Test.constTest,
-
Test.staticReadonlyTest);
-
Console.ReadLine();
-
}
-
}</span>
相同点:
- const与readonly都是只读的.
- const默认是static的,而且在编译期间已经解析完成.所以const与static readonly 只能由类来访问,而readonly由实例来访问.
不同点
- const既可以修饰类中的成员,又可以修饰函数体中的成员.而readonly只能修改类中的成员.
- const(静态常量)只能声明为简单的数据类型,如int,浮点型,枚举,布尔,字符串型.而readonly(动态常量)可以修饰一下对象类型,如Datetime类型.
注意:
- const默认是静态的,不能再static const!
- static readonly常量,如果要在构造函数中初始化其值,必须在静态无参构造函数中初始化.
总结:
const是静态常量,readonly是动态常量.const高效,readonly灵活!但实际开发中我们经常用static readonly 来代替const, 以平衡const在灵活性上的不足.
最近看到了readonly和const的区别,发现了一个自己的知识盲区,就是关于readonly的赋值问题。我的理解是对于readonly的一个变量,如果是值类型的,那么是这个变量的写操作是受限制的,如果是一个引用类型,那么保存的是这个变量的内存地址,对这个引用的写操作是受限制的,但是对于这个变量里面的成员的读写操作是不受限制的。具体可以看下面的一个例子。
-
using System;
-
using System.Collections.Generic;
-
using System.Linq;
-
using System.Text;
-
using System.Threading.Tasks;
-
namespace ConsoleApp1
-
{
-
class Program
-
{
-
public Program()
-
{
-
_testList.Add(123);
-
}
-
private readonly List<int> _testList = new List<int>();
-
static void Main(string[] args)
-
{
-
Program pro = new Program();
-
pro.Test();
-
Console.ReadKey();
-
}
-
private void Test()
-
{
-
Console.Write(_testList.Count+“ ”);
-
_testList.Add(1);
-
Console.Write(_testList.Count);
-
}
-
}
-
}
输出:1 2
可以看到这时候对_testList的添加操作是不受限制的,因为是改变了_testList里面的成员,而对于_testList里面保存的内存地址并没有改变,所以是可以添加的。
如果把 _testList.Add(1); 修改为 _testList = new List<int>;就会有报错,报错为:无法对只读的变量赋值(构造函数或变量初始值指定项中除外)。