贝利信息

c# const 和 readonly 的区别

日期:2026-01-09 00:00 / 作者:星降
const值编译时内联,更新需全量重编译;readonly运行时初始化,支持复杂类型和构造函数赋值,static readonly适用于跨程序集安全更新。

const 只能在编译时确定值,改了就得全量重编译

如果你把一个配置写成 const string ApiUrl = "https://api.example.com";,那这个字符串不是“存在内存里”,而是被 C# 编译器直接**替换进所有调用它的 IL 代码中**。这意味着:一旦你更新了这个常量、发布新版本的类库,但调用方没重新编译——它还在用旧地址。

readonly 支持运行时赋值,能用在构造函数和复杂类型上

readonly 字段不是“编译期硬编码”,而是在对象创建过程中(声明时或构造函数里)一次性赋值,之后禁止修改。它不挑类型,也不要求“编译期可算”。

public class ServiceClient
{
    public readonly int Timeout;
    public readonly DateTime CreatedAt;
    public readonly HttpClient Http;
public ServiceClient(int timeout)
{
    Timeout = timeout;              // ✅ 构造函数中赋值 OK
    CreatedAt = DateTime.UtcNow;   // ✅ DateTime 支持
    Http = new HttpClient();       // ✅ 引用类型也 OK
}

}

const 隐含 static,readonly 默认是实例级

你写 const int MaxRetries = 3;,它天然就是类级别的,只能通过 MyClass.MaxRetries 访问,不能用实例去点 —— 即使写了 var x = new MyClass(); x.MaxRetries,编译器也会报错。

  • readonly 字段默认属于实例:每个对象都有自己的一份副本(比如缓存路径、用户 ID 等)
  • 要让它变成类级别?加 static readonly,例如:static readonly string ConfigPath = Path.Combine(AppContext.BaseDirectory, "config.json");
  • 不能写 static const —— 语法错误,因为 const 已经是静态的了

选哪个?看三件事:能不能编译期确定、类型是否受限、要不要跨程序集安全更新

这不是风格偏好,而是行为差异带来的实际后果。尤其当你在写 NuGet 包或基础类库时,选错会埋坑。

  • 值是 int/string/enum,且确认永远不变 → 用 const(性能略高,无内存开销)
  • 值依赖构造参数、环境变量、配置文件、或类型是 List/DateTime/object → 必须用 readonly
  • 要发布给外部项目用?优先选 static readonly 而非 const,否则别人升级你的包却没重编译,就会拿到过期值

容易被忽略的一点:即使你用 readonly,也不能阻止反射强行修改(FieldInfo.SetValue(...)),但它至少守住编译期和常规运行时的契约。而 const 的“不可变”是编译器强制内联的结果,连反射都改不了——因为根本没字段存在。