readonly struct 是值类型,不能被修改
在 C# 中,
readonly struct表示整个结构体实例是不可变的:编译器会阻止对任何字段(包括
private字段)的赋值,除非发生在构造函数或字段初始化器中。它不等于“只读字段”,而是整个实例层面的写保护。
常见错误现象:
CS8342“Cannot assign to field '
xxx' because it is a readonly field of a readonly variable” —— 这通常出现在你试图修改
readonly struct的字段,或者通过
ref readonly返回后又尝试赋值时。 必须用
public readonly或
init(C# 9+)声明所有可访问字段;私有字段也得是
readonly,否则编译失败 构造函数里可以赋值,但之后所有路径(包括属性 setter、方法内部)都不能改字段 不能包含
ref返回字段的方法,也不能有可变的
get属性(比如返回
ref int) 性能影响小:编译器可能做内联优化,且避免了防御性拷贝(尤其传参时)
public readonly struct Point
{
public readonly int X;
public readonly int Y;
<pre class="brush:php;toolbar:false;">public Point(int x, int y) => (X, Y) = (x, y);
// ❌ 编译错误:无法在 readonly struct 中定义 set 访问器
// public int X { get; set; }}
readonly 成员(readonly member)是方法/属性级的只读约束
readonly修饰符加在方法、属性 getter、索引器或运算符上,表示该成员不会修改当前实例的状态。它和
readonly struct配合使用效果最好,但也能用于普通
struct或
class(class 中仅作语义提示,无强制约束)。
使用场景:当你想明确表达“这个方法只是读数据”,同时让编译器帮你检查是否意外写了字段;或配合
in参数提升性能。 在
readonly struct中,所有成员默认应为
readonly;若漏加,编译器会报
CS8656:“调用非 readonly 成员会丢弃 readonly 状态” 在普通
struct中加
readonly方法,能安全地被
readonly变量调用(否则会报错) 不能在
readonly方法中给任何实例字段赋值,也不能调用非
readonly成员 属性
get可以加
readonly,但
set不允许(语法不允许)
public readonly struct Rectangle
{
public readonly double Width;
public readonly double Height;
<pre class="brush:php;toolbar:false;">public Rectangle(double w, double h) => (Width, Height) = (w, h);
// ✅ 正确:readonly 方法,只读字段,不修改状态
public readonly double Area => Width * Height;
// ✅ 正确:显式 readonly getter
public readonly double Perimeter => 2 * (Width + Height);}
readonly 字段 vs readonly 成员:别混淆作用域
readonly字段(如
private readonly int _value;)控制的是字段本身能否被重新赋值;而
readonly成员控制的是「调用者能否通过这个成员改变实例」——两者粒度不同,常一起出现,但目的分离。
容易踩的坑:
readonly字段仍可被其类型内部修改(比如字段是
StringBuilder,你在
readonly方法里调
.Append()是合法的),这会让
readonly成员失去意义。所以真正安全的只读需要类型本身也是不可变的(如
string、
int、自定义
readonly struct)。
readonly字段可在构造函数、声明时初始化;
readonly成员只能加在方法、属性
get、索引器等成员上 字段是存储层面的约束,成员是行为层面的契约 对引用类型字段,
readonly只锁住“引用不变”,不锁住“对象内容不变” 如果 struct 包含可变引用类型字段(如
List<t></t>),即使加了
readonly成员,也无法保证逻辑只读
实际使用建议:从 readonly struct 开始,逐步收紧
不要一上来就给所有 struct 加
readonly;先确认它确实代表一个不可变概念(如坐标、颜色、时间区间)。然后补全
readonly成员,并用
in参数传递它以避免复制开销。 优先用
readonly struct替代普通
struct,尤其是作为 DTO、数学类型或高频传参场景 所有公开字段声明为
public readonly;私有字段也加
readonly(编译器要求) 每个方法、属性
get都显式加
readonly,除非你真需要修改状态(那它就不该是
readonly struct) 搭配
in参数使用:
void Process(in Rectangle r),此时编译器会确保只调用
readonly成员 注意兼容性:C# 7.2+ 才支持
readonly struct,旧项目升级需检查语言版本
最易被忽略的一点:readonly 不是线程安全的银弹。它只防止意外修改,不提供同步保障;多线程读同一个
readonly struct没问题,但若底层字段是共享可变对象(比如缓存的
Lazy<t></t>),仍需额外同步。
