C#怎么使用with表达式 C#record类型中with表达式怎么用如何创建对象的修改副本【语法】

张开发
2026/4/17 19:37:20 15 分钟阅读

分享文章

C#怎么使用with表达式 C#record类型中with表达式怎么用如何创建对象的修改副本【语法】
with表达式仅支持record类型含record class/struct不支持普通class或struct其为浅拷贝不递归复制引用对象init setter中调用with易致无限递归需避免。with 表达式只能用于 record 类型不是所有类都能用 with只有 record包括 record class 和 record struct才支持。普通 class 或 struct 写 obj with { Prop value } 会直接编译报错CS8852: Init-only property or indexer X can only be assigned in an object initializer, or on this in an instance constructor。常见错误是把老代码里的类改成 record 时漏掉 record 关键字或者误以为继承自 record 的子类自动获得 with 能力——其实不行子类也得显式声明为 record。record 是语法糖底层靠生成 Clone() init 属性 编译器合成的 With 方法实现如果类型里有非 init 的可变属性比如只有 set 没有 initwith 表达式不会修改它也不会报错容易误以为改成功了record struct 同样支持 with但要注意值类型的语义每次 with 都是新副本原变量不变with 会深拷贝还是浅拷贝with 表达式只做浅拷贝 —— 它复制字段值不递归复制引用对象。如果 record 里有个 Liststring 字段with 出来的新实例和原实例共享同一个 List 对象。这在多线程或后续修改集合时容易出问题。比如var r1 new Person(Alice, new Liststring { A });var r2 r1 with { Name Bob };r2.Hobbies.Add(B); // r1.Hobbies 也会变成 [A, B]想真正“不可变”嵌套的引用类型字段本身也得是 record 或不可变类型如 IReadOnlyListT、ImmutableArrayT没有银弹如果必须深拷贝得自己写逻辑with 不负责、也不支持指定深度with 对 null 字段照常赋值不会跳过或报空引用异常with 表达式中访问 this 成员要小心循环引用在 with 初始化器里不能直接用 this.Xxx 引用当前实例成员因为此时 this 尚未完成构造。但更隐蔽的问题是如果你在 record 的 init 属性 setter 里又调用了 with可能触发无限递归。典型场景是带验证逻辑的 init setter 稿定AI 拥有线稿上色优化、图片重绘、人物姿势检测、涂鸦完善等功能

更多文章