news 2026/4/28 13:18:52

深入解析 C# 中 const 与 readonly 的核心区别

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入解析 C# 中 const 与 readonly 的核心区别

在 C# 编程中,constreadonly经常被统称为“常量”,但二者在初始化规则、编译/运行时行为、IL 生成方式、版本兼容性、引用类型语义等方面存在本质差异。误用不仅可能引入隐蔽的逻辑错误,还会带来库升级后的版本陷阱


一、初始化位置:编译时强约束 vs 运行时一次性赋值

1️⃣const必须声明即赋值(编译期确定)

  • 必须在声明处赋值
  • 值在编译阶段就已确定
  • 任何位置都不能再次赋值(包括构造函数)
public class ConstantDemo { public const int MaxRetryCount = 3; public const string DefaultTitle = "C#常量解析"; // ❌ 编译错误:声明时未赋值 // public const double Pi; // ❌ 编译错误:不能在构造函数中修改 // public ConstantDemo() // { // MaxRetryCount = 5; // } }

📌结论const是“声明即终值”的编译期常量


2️⃣readonly声明时或构造函数中赋值(运行期确定)

  • 可以在声明处赋值
  • 也可以在实例构造函数 / 静态构造函数中赋值
  • 每个字段只允许赋值一次
public class ReadonlyDemo { // 声明时赋值 public readonly int MinAge = 18; // 构造函数中赋值 public readonly int UserId; public ReadonlyDemo(int userId) { UserId = userId; } // 静态 readonly:在静态构造函数中赋值 public static readonly string Version; static ReadonlyDemo() { Version = "1.0.1"; } }

📌结论readonly是“构造期冻结”的运行时常量。


二、修饰对象范围:字段 + 局部变量 vs 仅字段

const:字段 & 局部变量都支持

public class ConstScopeDemo { public const int GlobalConst = 100; public void LocalConstDemo() { const string LocalMsg = "局部常量"; Console.WriteLine(LocalMsg); } }

readonly只能修饰字段

public class ReadonlyScopeDemo { public readonly int FieldReadonly = 50; public void LocalReadonlyError() { // ❌ 编译错误:readonly 不能修饰局部变量 // readonly int x = 10; } }

三、编译期 vs 运行期:这是最本质的差异 ⭐⭐⭐

1️⃣const值被直接“内联”到 IL 中

public const int ConstValue = 10; public void UseConst() { int a = ConstValue; }

IL 行为本质

ldc.i4.s 10 // 直接压栈常量 10

⚠️重大隐患(版本陷阱)

  • 修改类库中的const
  • 引用方未重新编译
  • 引用方仍然使用旧值 ❌

2️⃣readonly始终通过字段访问(运行期绑定)

public readonly int ReadonlyValue; public ReadonlyDemo() { ReadonlyValue = 20; } public void UseReadonly() { int b = ReadonlyValue; }

IL 行为本质

ldfld int32 ReadonlyValue

✅ 修改值后,只需重新编译类库即可,调用方无需重新编译


四、静态语义:隐式静态 vs 显式静态

const天然 static,且禁止显式声明

public class ConstStaticDemo { public const int ConstStatic = 10; // ❌ 编译错误 // public static const int Invalid = 20; }

调用方式:

int x = ConstStaticDemo.ConstStatic;

readonly:默认实例级,静态需显式声明

public class ReadonlyStaticDemo { public readonly int InstanceReadonly = 100; public static readonly int StaticReadonly = 200; }

五、引用类型语义:值不可变 vs 引用不可变

const:仅支持string/null

public class ConstReferenceDemo { public const string ConstString = "Hello"; public const object ConstNull = null; // ❌ 编译错误 // public const List<int> ConstList = new List<int>(); }

原因:

  • const需要编译期确定值
  • string外,引用对象无法编译期确定

readonly:支持任意引用类型(但仅锁引用)

public class ReadonlyReferenceDemo { public readonly List<int> Numbers = new() { 1, 2, 3 }; public void Modify() { Numbers.Add(4); // ✅ 合法 // ❌ 编译错误:不能重新赋值 // Numbers = new List<int>(); } }

⚠️readonly≠ 不可变对象

  • 锁的是引用地址
  • 不是对象内容

六、完整对比速查表

维度constreadonly
初始化时机编译期运行期
赋值位置仅声明处声明 / 构造函数
修饰对象字段 + 局部变量仅字段
静态特性默认 static默认实例级
IL 行为内联常量字段访问
引用类型string / null任意引用类型
版本安全❌ 易出问题✅ 安全

七、工程化使用建议(非常重要)

✅ 优先使用const的场景

  • 数学常量(PIE
  • 永不变化的协议值、枚举值
  • 不会被类库外部依赖引用的内部常量
public const int MaxDays = 7;

✅ 推荐使用readonly的场景(真实项目更常见)

  • 类库对外暴露的“常量”
  • 配置读取、构造参数注入
  • 引用类型常量(集合、策略对象等)
public static readonly string ConnectionString; static DbConfig() { ConnectionString = LoadFromConfig(); }

八、一句话记忆法(面试 & 实战)

const是“编译期写死的字面量”
readonly是“构造期冻结的字段”


结语

constreadonly的差异,本质并不在“能不能改”,而在于:

  • 值是在什么时候决定的?(编译期 vs 运行期)
  • 是否参与 IL 内联?
  • 是否影响程序集版本兼容?

在真实工程中:

🔥99% 对外暴露的“常量”,都应该使用readonly而不是const

理解这一点,你就已经超过了大多数只停留在语法层面的 C# 开发者。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 5:40:58

LISA训练技术应用:动态注意力微调新范式

LISA训练技术应用&#xff1a;动态注意力微调新范式 在大模型时代&#xff0c;我们正面临一个看似矛盾的需求&#xff1a;既要让千亿参数的庞然大物快速适应千变万化的下游任务&#xff0c;又要在有限的显存和算力下完成这一切。传统的全量微调早已不堪重负——一次训练动辄几十…

作者头像 李华
网站建设 2026/4/23 19:26:24

Calibre电子书管理大师课:从零开始打造你的数字图书馆

在数字阅读时代&#xff0c;你是否曾被杂乱无章的电子书文件困扰&#xff1f;Calibre作为功能全面的开源电子书管理软件&#xff0c;能够帮助你轻松整理数字藏书库&#xff0c;实现各种格式的完美转换&#xff0c;让阅读管理变得前所未有的简单高效。本教程将带你从零开始&…

作者头像 李华
网站建设 2026/4/27 15:53:49

一文说清AUTOSAR通信栈的核心配置要点

搞定AUTOSAR通信配置&#xff0c;这三大模块你必须吃透在开发一辆现代智能汽车的ECU时&#xff0c;你有没有遇到过这样的场景&#xff1f;某个信号明明在发送端已经更新&#xff0c;接收端却迟迟“无动于衷”&#xff1b;或者仪表盘突然显示一个离谱的温度值——比如-400C&…

作者头像 李华
网站建设 2026/4/23 20:22:24

清华镜像级速度!一键拉取600+开源大模型权重

清华镜像级速度&#xff01;一键拉取600开源大模型权重 在当前AI研发的战场上&#xff0c;最让人头疼的不是算法设计&#xff0c;也不是算力不足&#xff0c;而是——连模型都还没开始训练&#xff0c;就已经卡死在下载权重这一步了。 你有没有经历过这样的场景&#xff1a;凌…

作者头像 李华
网站建设 2026/4/27 19:41:25

从BMP到C数组:LCD Image Converter操作指南

从BMP到C数组&#xff1a;嵌入式图像资源转换实战全解在做嵌入式开发时&#xff0c;你有没有遇到过这样的场景&#xff1f;产品经理递来一张精美的Logo图&#xff1a;“这个要显示在开机画面上。”设计师甩出一个PSD文件&#xff1a;“图标都做好了&#xff0c;直接用就行。”而…

作者头像 李华