为何C#的record struct无法包含init属性?
为什么C#的record struct不能生成get/init属性?
先看代码对比:
我的C#代码:
record struct recName(int A) { }
其幕后生成的代码如下:
internal struct recName : IEquatable<recName> { public recName(int A) { <A>k__BackingField = A; } private int <A>k__BackingField; public int A { get { return <A>k__BackingField; } set { <A>k__BackingField = value; } } }
而使用相同语法声明的record class:
record class recName(int A) { }
幕后生成的代码为:
internal class recName : IEquatable<recName> { public recName(int A) { <A>k__BackingField = A; } private readonly int <A>k__BackingField; public int A { get { return <A>k__BackingField; } init { <A>k__BackingField = value; } } }
核心原因在于值类型和引用类型的本质差异:
- record class是引用类型,设计初衷就是作为不可变(或半不可变)的数据承载类型,
init属性配合readonly字段,能确保对象初始化后无法被修改,完全契合record“数据不可变”的设计理念。 - record struct是值类型,值类型的实例本身是存储在栈(或作为结构体嵌入堆中)的直接值,而非引用。如果给record struct的自动属性生成
init,结合值类型特性会出现逻辑矛盾:值类型赋值是完整拷贝,即便字段标记readonly,拷贝后的新实例依然可以通过with表达式修改,但init的语义是“仅初始化阶段可修改”——值类型的拷贝本质是创建新实例,这会让init的语义变得模糊。
另外,C#团队在设计record struct时,考虑到值类型的常用场景往往需要可变性,因此默认生成带set的属性。如果需要不可变的record struct,只需显式声明readonly record struct,此时生成的属性就会是get/init,字段也会被标记为readonly:
示例代码:
readonly record struct recName(int A) { }
幕后生成的属性片段:
public int A { get { return <A>k__BackingField; } init { <A>k__BackingField = value; } }
内容的提问来源于stack exchange,提问作者FR3Y4
相关产品推荐
相关产品推荐

