在C#编程里,const和readonly都用于定义不可修改的值,但两者的底层逻辑和使用限制存在明显差异,理解这些差异是写出规范代码的基础。

const 的基本特性
const是编译时常量修饰符,它的值在编译阶段就会被确定并直接嵌入到使用它的代码位置,运行时无法修改。使用const有以下几个核心限制:
- 必须在声明的同时完成赋值,后续不能在构造函数或其他地方重新赋值
- 只能修饰基元类型(如int、string、double等)、枚举类型或者字符串类型,不能修饰自定义引用类型
- 隐式属于静态成员,不需要也不能添加static修饰符,调用时直接使用类名访问
下面是一个const的典型使用示例:
using System;
namespace ConstDemo
{
class Program
{
// 声明const常量,必须同时赋值
public const int MaxScore = 100;
public const string AppName = "成绩管理系统";
static void Main(string[] args)
{
// 直接通过类名访问const常量
Console.WriteLine($"应用名称:{Program.AppName},最高分数:{Program.MaxScore}");
// 尝试修改const值会直接编译报错
// Program.MaxScore = 90;
}
}
}
readonly 的基本特性
readonly是运行时常量修饰符,它的值可以在运行时确定,修饰的字段属于实例成员(如果添加static修饰则为静态成员)。readonly的核心特性如下:
- 可以在声明时赋值,也可以在构造函数中赋值,一旦赋值完成后就无法修改
- 可以修饰任意类型,包括基元类型、自定义引用类型、集合类型等
- 非静态的readonly字段属于实例成员,每个实例可以拥有不同的readonly值;静态readonly属于类级别的常量
下面是readonly的使用示例:
using System;
using System.Collections.Generic;
namespace ReadonlyDemo
{
class Student
{
// 声明时赋值
public readonly string SchoolName = "阳光小学";
// 声明时不赋值,在构造函数中赋值
public readonly int StudentId;
// 修饰引用类型
public readonly List<string> Courses;
public Student(int id)
{
// 构造函数中给readonly字段赋值
StudentId = id;
Courses = new List<string> { "语文", "数学" };
}
static void Main(string[] args)
{
Student stu1 = new Student(1001);
Student stu2 = new Student(1002);
Console.WriteLine($"学生1学校:{stu1.SchoolName},学号:{stu1.StudentId}");
Console.WriteLine($"学生2学校:{stu2.SchoolName},学号:{stu2.StudentId}");
// 尝试修改readonly字段会编译报错
// stu1.StudentId = 1003;
}
}
}
两者的核心区别对比
通过下表可以清晰看到const和readonly的差异:
| 对比维度 | const | readonly |
|---|---|---|
| 常量类型 | 编译时常量 | 运行时常量 |
| 赋值时机 | 声明时必须赋值,后续不可修改 | 声明时或构造函数中赋值,后续不可修改 |
| 修饰类型限制 | 仅支持基元类型、枚举、字符串 | 支持所有数据类型 |
| 成员属性 | 隐式静态,无需static修饰 | 默认是实例成员,可加static变为静态成员 |
| 内存相关 | 值直接嵌入IL代码,无独立内存地址 | 有独立的内存地址,运行时分配 |
使用场景建议
在实际开发中可以按照以下规则选择:
- 如果值是永远不会改变的基元类型或字符串,比如数学常量、固定配置项,优先使用const,因为它的性能更好
- 如果值需要在运行时确定,比如通过配置文件读取的初始值、不同实例有不同值的不可变属性,或者要修饰引用类型,就使用readonly
- 如果需要定义静态的、运行时初始化的不可变值,可以使用static readonly的组合
需要注意的是,如果在一个程序集中定义了const常量,另一个程序集引用了这个常量,那么修改第一个程序集的const值后,第二个程序集需要重新编译才能获取到新值;而readonly的值修改后,只要接口不变,引用方不需要重新编译也能获取到新值。
总结来说,const是编译期确定的静态不可变值,readonly是运行期确定的不可变值,根据值的确定时机和类型需求选择即可。