You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 14:22:09