news 2026/6/10 21:18:09

深入解析 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/6/10 10:57:25

零基础快速上手:Wan2.2-S2V-14B模型下载与视频生成完整攻略

零基础快速上手&#xff1a;Wan2.2-S2V-14B模型下载与视频生成完整攻略 【免费下载链接】Wan2.2-S2V-14B 【Wan2.2 全新发布&#xff5c;更强画质&#xff0c;更快生成】新一代视频生成模型 Wan2.2&#xff0c;创新采用MoE架构&#xff0c;实现电影级美学与复杂运动控制&#x…

作者头像 李华
网站建设 2026/6/10 11:20:45

loss-scale机制解析:混合精度训练稳定性保障

loss-scale机制解析&#xff1a;混合精度训练稳定性保障 在当今大模型时代&#xff0c;一个70亿参数的LLM用FP32训练需要超过140GB显存——这几乎无法在单卡上运行。而通过混合精度训练&#xff0c;我们能将这一数字压缩近半&#xff0c;甚至在消费级显卡上完成微调任务。但随之…

作者头像 李华
网站建设 2026/6/10 11:39:45

foobox-cn深度体验:打造你的专属音乐播放中心

foobox-cn深度体验&#xff1a;打造你的专属音乐播放中心 【免费下载链接】foobox-cn DUI 配置 for foobar2000 项目地址: https://gitcode.com/GitHub_Trending/fo/foobox-cn 还在为foobar2000的简陋界面而烦恼&#xff1f;想要一个既美观又功能强大的音乐播放体验&…

作者头像 李华
网站建设 2026/6/10 10:55:00

解锁重庆地形密码:这份DEM数据集让你玩转三维地理分析 [特殊字符]️

解锁重庆地形密码&#xff1a;这份DEM数据集让你玩转三维地理分析 &#x1f5fa;️ 【免费下载链接】重庆地区DEM数据集 探索重庆的地理奥秘&#xff0c;这份DEM数据集为你提供了详尽的高程、等高线与路网信息。无论是专业GIS分析还是三维可视化&#xff0c;tif、kmz和kml格式的…

作者头像 李华
网站建设 2026/6/9 23:53:05

LaunchKit终极指南:如何快速构建移动应用全生命周期管理平台

LaunchKit终极指南&#xff1a;如何快速构建移动应用全生命周期管理平台 【免费下载链接】LaunchKit A set of web-based tools for mobile app developers, now open source! 项目地址: https://gitcode.com/gh_mirrors/la/LaunchKit LaunchKit是一套专为移动应用开发者…

作者头像 李华
网站建设 2026/6/10 10:56:05

入门必看:rs232串口通信原理图常见符号与含义说明

从零读懂RS232原理图&#xff1a;那些你常看到却叫不出名字的符号&#xff0c;到底在说什么&#xff1f;你有没有过这样的经历&#xff1f;打开一块开发板的原理图&#xff0c;满屏都是“TXD”、“RXD”、“GND”&#xff0c;中间还夹着个神秘的MAX232芯片和一个9针的DB9接口。…

作者头像 李华