ref readonly参数是编译器强制只读语义与零拷贝访问的组合机制,要求传入可寻址左值(如变量、字段、数组元素),禁止传new表达式、方法返回值等右值,且方法体内不可调用非readonly成员。

ref readonly 参数不是“更安全的 ref”,而是编译器强制执行只读语义 + 零拷贝访问的组合机制——它只在传入可寻址左值时生效,传右值直接编译失败,且方法体内连非 readonly 的只读属性(如 ToString())都不能调用。
ref readonly 参数为什么不能传 new 表达式或方法返回值
因为 ref readonly 要求参数必须是“有稳定内存地址”的左值。临时对象(如 new BigStruct())、方法调用结果(如 GetMatrix())、属性访问(如 obj.Data)都不满足该条件。
- 编译器报错
CS8337:“Cannot use a result of 'new T()' as a ref or out value because it is not a variable” - 即使结构体很小,比如
struct Point { public int X,Y; },Process(ref readonly new Point())也非法 - 合法传入源仅限:局部变量、字段、数组元素、
Span<t></t>索引、其他ref readonly参数
ref readonly 和 in 参数的区别到底在哪
in 是 ref readonly 的语法糖,但二者适用范围不同:前者只能用于参数,后者还能用于返回值、局部变量、字段;而 in 在调用端可省略关键字(不推荐),ref readonly 必须显式写出。
-
in参数本质就是编译器自动转成ref readonly,但禁止你把它再传给非in或非ref readonly的形参 -
in不能用于async方法或yield迭代器;ref readonly同样受限,且额外禁止用于out/ref重载区分 - 性能上无差别,但
in更简洁;若需返回只读引用(如ref readonly T GetRef(int i)),只能用ref readonly
ref readonly 方法内哪些操作会触发编译错误
编译器会严格检查所有通过该参数发生的成员访问,只要涉及“可能写入”就拒绝——哪怕逻辑上没改,只要签名没标 readonly 就算违规。
-
param.Field = 42;→ 报错:Cannot assign to field 'Field' because it is a readonly field of a readonly variable -
param.SomeMethod();→ 若SomeMethod没声明为readonly,报错:CS8656: Calling a non-readonly member... -
param.ToString();→ 即使ToString()实际没改状态,因基类未标记readonly,仍报错 - 允许的操作:读字段、调用
readonly方法、访问readonly属性 getter、赋值给本地变量(复制后可改)
ref readonly 返回值的生命周期陷阱
和 ref 返回一样,ref readonly 返回值必须指向“不会随方法退出而销毁”的内存。但比 ref 更隐蔽的是:它还拒绝返回临时结构体的字段引用。
-
return ref readonly _array[i];✅(字段/数组元素,生命周期由宿主控制) -
return ref readonly localStruct.Field;❌(localStruct是栈变量,退出即失效) -
return ref readonly GetStruct().Field;❌(GetStruct()返回临时值,其字段地址无效) - 若返回结构体字段,该结构体最好声明为
readonly struct,否则编译器可能因“隐式复制风险”报错CS2026
真正容易被忽略的点是:即便你确保了返回源合法,如果被引用的结构体本身没标记 readonly struct,且字段又不是 public readonly,编译器可能在某些版本(如 .NET SDK 8.0.300+)中额外拦截——这不是 bug,而是对“只读契约完整性”的强化检查。










