在C#编程中,const和readonly都用于定义不可修改的值,但两者的底层逻辑和使用限制存在明显差异,这也是面试中经常被问到的知识点。很多开发者平时使用时只关注不可修改的特性,却忽略了两者的核心区别,导致面试时回答不完整。

一、基本定义与核心特性
1. const常量
const是编译时常量,在编译阶段就会被替换为对应的值,定义时必须初始化,且初始化的值必须是编译期可确定的常量表达式。const修饰的变量默认是静态的,不需要也不能用static修饰。
支持的类型有限,仅包括值类型(除DateTime外)、string类型、枚举类型,并且不能修饰引用类型的实例(除了string这种特殊的不可变类型)。
// const定义示例
public class ConstDemo
{
// 必须初始化,编译期确定值
public const int MaxCount = 100;
public const string AppName = "TestApp";
// 错误示例:不能延迟初始化
// public const int MinCount;
}
2. readonly只读字段
readonly是运行时常量,值在运行阶段确定,可以在声明时初始化,也可以在构造函数中初始化,每个实例可以拥有不同的readonly值。readonly不是静态的,如果需要类级别的只读值,需要配合static修饰。
支持几乎所有类型,包括值类型和引用类型,引用类型的readonly字段只是引用不可修改,引用的对象内部属性可以修改。
// readonly定义示例
public class ReadonlyDemo
{
// 声明时初始化
public readonly int DefaultScore = 60;
// 构造函数中初始化,不同实例可以有不同值
public readonly string UserName;
public ReadonlyDemo(string name)
{
UserName = name;
}
// 静态只读字段
public static readonly DateTime StartTime;
static ReadonlyDemo()
{
StartTime = DateTime.Now;
}
}
二、核心区别对比
| 对比维度 | const | readonly |
|---|---|---|
| 赋值时机 | 编译期,必须声明时初始化 | 运行期,可声明时或构造函数初始化 |
| 静态特性 | 默认静态,无需static修饰 | 默认实例级,静态需加static |
| 支持类型 | 值类型(除DateTime)、string、枚举 | 所有类型 |
| 修改限制 | 完全不可修改,编译后直接替换值 | 只能在构造函数中修改,之后不可改 |
| 引用类型限制 | 仅支持string不可变类型 | 引用不可改,对象内容可改 |
三、引用类型的差异示例
const修饰引用类型时仅支持string,而readonly修饰引用类型时,引用本身不可修改,但引用的对象内部可以变化,这是两者很重要的区别。
public class Person
{
public string Name { get; set; }
}
public class RefTypeDemo
{
// 错误:const不能修饰非string的引用类型
// public const Person DefaultPerson = new Person();
// readonly修饰引用类型
public readonly Person ReadonlyPerson = new Person { Name = "初始" };
public void Test()
{
// 错误:引用不可修改
// ReadonlyPerson = new Person();
// 正确:引用对象的内容可以修改
ReadonlyPerson.Name = "修改后";
}
}
四、适用场景与面试答题思路
面试中回答两者的区别时,可以按照定义、赋值时机、支持类型、使用场景的逻辑展开,同时结合例子说明。
- 如果值是编译期确定的固定值,比如数学常量、固定配置项,优先使用const,性能更好,因为编译后直接替换值,没有运行时开销。
- 如果值需要运行期确定,比如从配置文件读取、根据构造函数参数赋值,或者需要修饰引用类型,优先使用readonly。
- 需要注意如果const的值被修改,所有引用该const的程序集都需要重新编译,而readonly修改后只需要重新编译当前程序集,这也是跨程序集引用时的注意点。
常见面试追问:const能不能修饰DateTime?答案是不能,因为DateTime不是编译期可确定的常量表达式,这种情况需要用static readonly代替。
// 正确替代方式 public static readonly DateTime ReleaseDate = new DateTime(2024, 1, 1);