news 2026/4/23 9:33:51

深入解析 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/21 23:16:48

MediaPipe Samples完整指南:5分钟构建高性能机器学习应用

MediaPipe Samples完整指南&#xff1a;5分钟构建高性能机器学习应用 【免费下载链接】mediapipe-samples 项目地址: https://gitcode.com/GitHub_Trending/me/mediapipe-samples 还在为机器学习应用开发的高门槛而烦恼吗&#xff1f;面对复杂的模型部署、跨平台兼容性…

作者头像 李华
网站建设 2026/4/20 9:57:04

模仿排雷游戏,写北极狐抓旅鼠游戏,北极狐冬季食物极度缺乏,旅鼠却衣食无忧,肥肥胖胖,在一平方公里范围,北极狐可能成功,也可能失败,旅鼠身上数字代表周围有几只旅鼠。

我将为您设计一个完整的北极狐捕捉旅鼠游戏。这个游戏包含了您要求的所有核心模块。#include <iostream>#include <vector>#include <string>#include <cstdlib>#include <ctime>#include <conio.h>#include <windows.h>using names…

作者头像 李华
网站建设 2026/4/15 19:33:19

USB Burning Tool使用全解析:智能电视盒子专用方案

USB Burning Tool实战全指南&#xff1a;从救砖到量产&#xff0c;玩转Amlogic电视盒子底层烧录 你有没有遇到过这样的场景&#xff1f;手里的电视盒子突然开不了机&#xff0c;卡在LOGO界面无限重启&#xff0c;OTA升级失败&#xff0c;ADB进不去——典型的“变砖”症状。这时…

作者头像 李华
网站建设 2026/4/19 17:20:55

探索Intel RealSense:解锁深度视觉开发的无限可能

探索Intel RealSense&#xff1a;解锁深度视觉开发的无限可能 【免费下载链接】librealsense Intel RealSense™ SDK 项目地址: https://gitcode.com/GitHub_Trending/li/librealsense 在当今计算机视觉快速发展的时代&#xff0c;Intel RealSense深度摄像头以其强大的3…

作者头像 李华
网站建设 2026/4/23 9:33:40

vivado安装教程2018小白指南:避开安装过程中的坑

Vivado 2018 安装实战指南&#xff1a;从零开始避坑&#xff0c;一次成功 你是不是也经历过这样的场景&#xff1f; 满怀期待地打开电脑准备入门 FPGA 开发&#xff0c;结果在第一步—— 安装 Vivado 的时候就被卡住 &#xff1a;程序打不开、解压失败、启动报错 DLL 缺失……

作者头像 李华
网站建设 2026/4/2 19:32:22

终极指南:快速搭建AI模型服务网关与智能路由系统

终极指南&#xff1a;快速搭建AI模型服务网关与智能路由系统 【免费下载链接】claude-code-router Use Claude Code without an Anthropics account and route it to another LLM provider 项目地址: https://gitcode.com/GitHub_Trending/cl/claude-code-router 还在为…

作者头像 李华