C# 只读成员readonly方法 C# readonly struct和readonly member如何使用

来源:这里教程网 时间:2026-02-21 17:41:23 作者:

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>
),仍需额外同步。

相关推荐