0Pricing
C# Academy · 课时

记录类型中的 with 表达式

创建不可变对象的修改副本。

记录类型中的 with 表达式 是 CoddyKit 上的免费 C# Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

非破坏性复制表达式

with 表达式会创建记录的副本,并更改其中的部分属性,同时保持原记录不变。它是“更新”不可变记录的惯用方式。

using System;

record Point(int X, int Y);

var a = new Point(1, 2);
var b = a with { Y = 9 };
Console.WriteLine(a + " | " + b); // Point { X = 1, Y = 2 } | Point { X = 1, Y = 9 }

非破坏性变更

原记录永远不会被修改。with 会执行浅复制,并且只将列出的更改应用到副本。

using System;

record User(string Name, int Age);

var original = new User("Ada", 30);
var older = original with { Age = 31 };
Console.WriteLine(original.Age + " " + older.Age); // 30 31

更改多个属性

您可以在大括号内列出多个赋值,一次更改多个属性。

using System;

record Config(string Env, int Retries, bool Verbose);

var baseCfg = new Config("dev", 3, false);
var prod = baseCfg with { Env = "prod", Verbose = true };
Console.WriteLine(prod.Env + " " + prod.Retries + " " + prod.Verbose); // prod 3 True

复制未更改的属性

您未提及的属性会原样从源记录复制过来。

using System;

record Product(string Name, decimal Price, int Stock);

var p = new Product("Book", 12m, 5);
var discounted = p with { Price = 10m };
Console.WriteLine(discounted.Name + " " + discounted.Stock); // Book 5

非破坏性更新与值相等性

由于记录使用值相等性,因此不做任何更改的副本与原记录相等。

using System;

record Coord(int X, int Y);

var a = new Coord(1, 2);
var b = a with { };
Console.WriteLine(a == b);         // True (value equal)
Console.WriteLine(ReferenceEquals(a, b)); // False (different objects)

浅复制语义

with复制的是引用,而不是完整的对象图。原记录与副本会共享同一个嵌套可变对象。

using System;
using System.Collections.Generic;

record Cart(List<string> Items);

var a = new Cart(new List<string> { "x" });
var b = a with { };
b.Items.Add("y"); // shared list!
Console.WriteLine(a.Items.Count); // 2

记录结构中的非破坏性更新

记录结构同样支持with,从而生成值类型的修改副本。

using System;

record struct Size(int W, int H);

var s = new Size(4, 4);
var wide = s with { W = 8 };
Console.WriteLine(wide.W + "x" + wide.H); // 8x4

串联非破坏性更新表达式

您可以串联with表达式,依次应用一系列更改,每次都会生成一条新记录。

using System;

record Point(int X, int Y, int Z);

var p = new Point(0, 0, 0)
    with { X = 1 }
    with { Y = 2 }
    with { Z = 3 };
Console.WriteLine(p); // Point { X = 1, Y = 2, Z = 3 }

无需构建器的更新

with无需使用构建器类:只需复制对象,然后调整所需的字段即可。

using System;

record Email(string To, string Subject, string Body);

var draft = new Email("a@b.com", "Hi", "");
var ready = draft with { Body = "Welcome!" };
Console.WriteLine(ready.Body); // Welcome!

自定义复制逻辑

记录会生成一个受保护的复制构造函数,with会使用它。您可以自行声明复制构造函数,以自定义复制方式。

using System;

record Audited(string Name) {
    public int Version { get; init; } = 1;
    protected Audited(Audited other) {
        Name = other.Name;
        Version = other.Version + 1; // bump on every copy
    }
}

var a = new Audited("x");
var b = a with { };
Console.WriteLine(a.Version + " " + b.Version); // 1 2

综合运用

使用with建模状态转换,可以保留便于审计的不可变历史记录。

using System;

record Order(string Id, string Status);

var created = new Order("O1", "Created");
var paid = created with { Status = "Paid" };
var shipped = paid with { Status = "Shipped" };
Console.WriteLine(created.Status + " -> " + paid.Status + " -> " + shipped.Status);

快速检查

请检验您对 with 表达式的理解。

回顾

您已经学习了记录的with表达式。

  • a with { Prop = value }会复制对象并更改选定的属性。
  • 原对象永远不会被修改;这是非破坏性的。
  • 副本是浅副本,因此嵌套的可变对象会被共享。
  • 它适用于记录和记录结构,也可以串联使用。

常见问题解答

「记录类型中的 with 表达式」课时是免费的吗?

是的 — 「记录类型中的 with 表达式」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「记录类型中的 with 表达式」这节课中我会学到什么?

创建不可变对象的修改副本。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「记录类型中的 with 表达式」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 仅限 init 的 setter
  2. required 修饰符
  3. 不可变对象模式
  4. 记录类型中的 with 表达式
← 返回 C# Academy