C# - readonly 和 const 关键字
引言
程序设计过程中经常会用到常量,C# 语言中有 readonly
, const
定义常量,如何准确的定义常量,它们的区别又是什么?
静态常量和动态常量
在了解这两个关键字之前,我们先来了解一下静态常量和动态常量。
- 静态常量:
在编译时就确定了值,必须在声明时就进行初始化且之后不能进行更改。 - 动态常量:
在运行时确定值,只能在声明时或构造函数中初始化。
const
使用 const
关键字来声明某个常量字段或常量局部变量,是静态常量。 常量字段和常量局部变量不能含变量并且不能修改。 常量可以为数字、布尔值、字符串或 null 引用。 不要创建常量来表示你需要随时更改的信息。
const 注意事项
-
const
和static
不能一起使用,因为常量字段是隐式静态的,const
编译之后就是static
静态字段。
-
不能用
new
关键字初始化一个静态常量,即便是对一个值类型来说
-
const 常量不能是变量
const 常量访问
类直接访问 const
常量。
namespace ConsoleApp1
{
class SampleClass
{
public int x;
public int y;
public const int C1 = 5;
public const int C2 = C1 + 5;
public SampleClass(int p1, int p2)
{
x = p1;
y = p2;
}
}
public class TestConst
{
public static void Main(string[] args)
{
var mC = new SampleClass(11, 22);
Console.WriteLine($"x = {mC.x}, y = {mC.y}");
Console.WriteLine($"C1 = {SampleClass.C1}, C2 = {SampleClass.C2}");
}
}
}
/* Output
x = 11, y = 22
C1 = 5, C2 = 10
*/
readonly
readonly
只能在声明期间或在同一个类的构造函数中向字段赋值。 可以在字段声明和构造函数中多次分配和重新分配只读字段,属于动态常量。
static readonly
静态只读字段,只读字段不是隐式静态的,所以要在类级别公开,就必须显式使用 static
关键字。
构造函数退出后,不能分配 readonly
字段。 此规则对于值类型和引用类型具有不同的含义:
- 由于值类型直接包含数据,因此属于 readonly 值类型的字段不可变。
- 由于引用类型包含对其数据的引用,因此属于 readonly 引用类型的字段必须始终引用同一对象。 该对象是可变的。 readonly 修饰符可防止字段替换为引用类型的其他实例。 但是,修饰符不会阻止通过只读字段修改字段的实例数据。
readonly 常量访问
namespace ConsoleApp1
{
class SamplePoint
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public static readonly string LAGUAGE = "C#";
public SamplePoint()
{
// Initialize a readonly instance field
z = 24;
}
public SamplePoint(int p1, int p2, int p3)
{
x = p1;
y = p2;
z = p3;
}
}
public class TestConst
{
public static void Main(string[] args)
{
Console.WriteLine($"SamplePoint.LAGUAGE = {SamplePoint.LAGUAGE}");
SamplePoint p1 = new SamplePoint(11, 21, 32); // OK
Console.WriteLine($"p1: x={p1.x}, y={p1.y}, z={p1.z}");
SamplePoint p2 = new SamplePoint();
p2.x = 55; // OK
//p2.y = 66;// Error
Console.WriteLine($"p2: x={p2.x}, y={p2.y}, z={p2.z}");
}
}
}
/* output
SamplePoint.LAGUAGE = C#
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
*/
const 和 readonly 区别
- 概念上的区别
readonly
表示只读,动态常量,运行时确定值,const
表示静态常量,编译时就确定值。
比如:人的出生日期就可以定义成const
常量,值一旦申明就不会发生变化,而人的年龄 age 可以定义成readonly
, 可以在构造函数中根据出生日期计算年龄。 - 修饰范围区别
readonly
只能修饰 field,不能修饰 local variable,const
可修饰 field 和 local variable。
- 类型区别
const
只能修饰 primitive type(数字、布尔值,字符) 以及很特殊的引用类型 string 和 null(string是不可变字符串,每次修改,都相当于重新创建了一个),为什么不能修饰其他的引用类型,因为其他的引用类型在编译期不能知道他们的确切值。不能用new
关键字初始化一个静态常量。
readonly
可以是任意数据类型,可以用new
关键字初始化一个动态常量。 const
变量默认是static
类变量,不能加static
修饰,readonly
默认不是,需要特意加上 static 才能变成类变量。- 赋值
const
只能在申明时赋值,不能外部赋值,readonly
可以外部赋值,但只能通过构造函数赋值。 - 效率
const
修饰的常量注重的是效率;readonly
修饰的常量注重灵活。
const
修饰的常量没有内存消耗;readonly
因为需要保存常量,所以有内存消耗。