const值编译时内联,更新需全量重编译;readonly运行时初始化,支持复杂类型和构造函数赋值,static readonly适用于跨程序集安全更新。

const 只能在编译时确定值,改了就得全量重编译
如果你把一个配置写成 const string ApiUrl = "https://api.example.com";,那这个字符串不是“存在内存里”,而是被 C# 编译器直接**替换进所有调用它的 IL 代码中**。这意味着:一旦你更新了这个常量、发布新版本的类库,但调用方没重新编译——它还在用旧地址。
- 常见错误现象:
ApiUrl在类库中已改成"https://new-api.example.com",但老客户端仍请求旧地址,且日志/调试都看不出问题 - 适用场景:数学常量(
const double Pi = 3.14159;)、固定协议标识(const string ContentTypeJson = "application/json";)这类真正“永不变”的值 - 不能用于需要运行时计算的值,比如
DateTime.Now.ToString()或Environment.GetFolderPath(...)—— 编译器直接报错
readonly 支持运行时赋值,能用在构造函数和复杂类型上
readonly 字段不是“编译期硬编码”,而是在对象创建过程中(声明时或构造函数里)一次性赋值,之后禁止修改。它不挑类型,也不要求“编译期可算”。
- 支持任意类型:数组、自定义类、
DateTime、Guid、甚至HttpClient实例(只要确保只初始化一次) - 可以是实例级或静态级:
readonly string InstanceId每个对象不同;static readonly Guid AppId全局一份 - 常见错误:在普通方法里试图赋值
this.Timeout = 30;→ 编译错误 CS0198:“无法对只读字段赋值”
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,编译器也会报错。
网钛淘拍CMS(TaoPaiCMS) V1.60
2013年07月06日 V1.60 升级包更新方式:admin文件夹改成你后台目录名,然后补丁包里的所有文件覆盖进去。1.[新增]后台引导页加入非IE浏览器提示,后台部分功能在非IE浏览器下可能没法使用2.[改进]淘客商品管理 首页 列表页 内容页 的下拉项加入颜色来区别不同项3.[改进]后台新增/修改淘客商品,增加淘宝字样的图标和天猫字样图标改成天猫logo图标4.[改进]为统一名称,“分类”改
下载
-
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 的“不可变”是编译器强制内联的结果,连反射都改不了——因为根本没字段存在。









