记录类型中的 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 反馈 — 无需本地设置。
此课程中的所有课时
- 仅限 init 的 setter
- required 修饰符
- 不可变对象模式
- 记录类型中的 with 表达式