在 C# 中,readonly 和 const 都是用于限制变量修改的关键字,但它们的作用时机适用场景特性有显著区别。结合你的代码示例,具体解释如下:

1. const(常量)—— 编译时确定的不可变值

代码示例:

private const int GripSize = 8;//控制点的矩形长宽
核心特性:
  • 编译时常量const 修饰的变量值在编译阶段就已确定,并被嵌入到编译后的代码中(类似 “硬编码”)。运行时无法修改,也不会分配独立的内存空间。
  • 必须在声明时初始化:声明时必须赋值,且值必须是 “编译时可计算的常量”(如数值、字符串、枚举值等),不能依赖运行时才能确定的值(如变量、方法返回值)。
  • 适用类型有限:只能修饰值类型(如 intfloatbool)或字符串(string,不能修饰引用类型(如 List<Shape>object 等)。
  • 作用域内共享const 是 “类型级别的常量”,所有实例共享同一个值,不存在 “每个实例一个常量” 的情况。
在代码中的意义:

GripSize 表示 “控制点的矩形长宽”(如选中 ROI 时边缘显示的小方块大小),这个值是固定不变的(业务上不需要动态调整)。用 const 修饰的原因:

  • 编译时确定值,访问效率极高(直接读取硬编码的值);
  • 明确告知编译器和开发者:这个值永远不会变,避免意外修改。

2. readonly(只读字段)—— 运行时确定的不可变引用

代码示例:

private readonly List<Shape> shapes = new List<Shape>();//ROI集合
核心特性:
  • 运行时常量readonly 修饰的字段值在运行时确定,可以在声明时初始化,也可以在构造函数中初始化(但只能初始化一次)。
  • 不可二次赋值:对象创建后(构造函数执行完毕),readonly 字段的引用(或值)不能被修改。但如果是引用类型(如集合、类实例),其内部内容可以修改(仅限制 “引用本身不可变”)。
  • 适用类型广泛:可以修饰任何类型(值类型、引用类型均可)。
  • 实例级别的只读:每个类实例可以有自己的 readonly 字段值(如果在构造函数中根据参数初始化)。
在代码中的意义:

shapes 是存储 ROI 的集合(List<Shape>),用 readonly 修饰的原因:

  • 确保 shapes 这个字段不能被重新赋值为另一个 List<Shape> 实例(避免意外替换整个集合);
  • 但允许修改集合的内部内容(如通过 shapes.Add() 添加 ROI、shapes.Remove() 删除 ROI),这符合业务需求(ROI 集合需要动态增删,但集合本身不能被替换);
  • 可以在构造函数中根据需要初始化(例如从外部加载已有 ROI 到集合中),灵活性高于 const

const vs readonly 关键区别总结

特性 const readonly
确定时机 编译时 运行时(构造函数执行时)
初始化位置 必须在声明时 声明时或构造函数中
可修饰类型 仅值类型、字符串、枚举 任何类型(值类型、引用类型)
能否修改 永远不能修改 构造函数执行后不能修改(引用不变)
引用类型处理 不支持(无法修饰引用类型) 允许修改内部内容(仅限制引用本身)

总结

  • const 用于编译时就确定且永不改变的简单值(如固定尺寸、常量参数),例如代码中的 GripSize(控制点大小固定)。
  • readonly 用于运行时初始化且引用(或值)不可二次修改的字段,尤其适合引用类型(如集合、对象),例如代码中的 shapes(集合本身不能被替换,但内容可动态修改)。

两者的核心目的都是 “限制修改”,但根据值的确定时机和类型选择使用,以保证代码的安全性和合理性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐