Chapter 11. Composition using tuples
覆盖C# 7 tuple literals、tuple types、conversions、ValueTuple CLR表示、替代方案与使用边界,按arity、position、names和ownership判断设计。
学习目标
- 能从tuple literal推导arity、element types与names,解释compile-time tuple type和runtime ValueTuple表示的差异
- 能逐position判断tuple conversions、assignment、equality与name warnings,不把element names误当runtime identity
- 能设计tuple、anonymous type或nominal type的选择规则,并按ownership、invariant、versioning和consumer radius验证public API演进风险
机制总览
Chapter 11. Composition using tuples:机制路径
- 1
为什么Tuple适合临时组合而不是自动替代领域模型
方法经常需要返回两个相关结果,LINQ pipeline也会临时携带value与index。C 7 tuples让这种composition有静态types和可读element names,不必为每个局部shape声明class。它的力量来自低ceremony,也因此缺少nominal type可以…
- 2
Introduction to tuples
Tuple表示固定长度、按position排列的heterogeneous values。与 System.Tuple reference types相比,C 7语法通常映射到 System.ValueTuple value types,并允许source层的element names。它适合pri…
- 3
Tuple literals and tuple types
Literal (id: 42, total: 9.5m) 可target为显式 (int id, decimal total) ,也可由 var 推断。Simple variable/member expressions可产生inferred names;其他expression退回 Item1 …
章级决策实验
Chapter 11. Composition using tuples:机制与证据
切换《Chapter 11. Composition using tuples》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。
选择推理阶段
当前阶段 · 为什么Tuple适合临时组合而不是自动替代领域模型
方法经常需要返回两个相关结果,LINQ pipeline也会临时携带value与index。C 7 tuples让这种composition有静态types和可读element names,不必为每个局部shape声明class。它的力量来自低ceremony,也因此缺少nominal type可以…
可核验证据
以明确的 LangVersion 与目标框架构建「为什么Tuple适合临时组合而不是自动替代领域模型」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
学完《Chapter 11. Composition using tuples》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。
失效—证据矩阵
Chapter 11. Composition using tuples:失效与核验
为什么Tuple适合临时组合而不是自动替代领域模型
典型失效
若解释「为什么Tuple适合临时组合而不是自动替代领域模型」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。
核验证据
以明确的 LangVersion 与目标框架构建「为什么Tuple适合临时组合而不是自动替代领域模型」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
Introduction to tuples
典型失效
若解释「Introduction to tuples」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。
核验证据
以明确的 LangVersion 与目标框架构建「Introduction to tuples」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
Tuple literals and tuple types
典型失效
若解释「Tuple literals and tuple types」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。
核验证据
以明确的 LangVersion 与目标框架构建「Tuple literals and tuple types」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
为什么Tuple适合临时组合而不是自动替代领域模型
方法经常需要返回两个相关结果,LINQ pipeline也会临时携带value与index。C# 7 tuples让这种composition有静态types和可读element names,不必为每个局部shape声明class。它的力量来自低ceremony,也因此缺少nominal type可以承载的constructor validation、methods、documentation与独立version identity。
先预测:(int x, int y)与(int width, int height)是否是不同runtime types;element names是否参与equality;八元素tuple是否只有八个flat CLR fields;public method只改返回tuple element name是否毫无兼容性影响。答案依次是“不是、否、否、不能这样保证”。
Introduction to tuples
Tuple表示固定长度、按position排列的heterogeneous values。与System.Tuple reference types相比,C# 7语法通常映射到System.ValueTuple value types,并允许source层的element names。它适合private helper return、短生命周期pipeline state与清楚稳定的dictionary key。
Tuple不是collection:arity与每个position type都是compile-time shape的一部分,不能在runtime append element。也不要把“有两个string”当作足够语义;若first/last、source/destination容易交换,nominal wrapper可能更安全。
Tuple literals and tuple types
Literal (id: 42, total: 9.5m)可target为显式(int id, decimal total),也可由var推断。Simple variable/member expressions可产生inferred names;其他expression退回Item1等访问。Names提高source readability,却不是value携带的独立runtime fields。
(int id, decimal total) summary = (order.Id, order.Total);
var inferred = (order.Id, order.Total); // inferred names: Id, Total
Console.WriteLine($"{summary.id}: {summary.total}");切换literal、inferred names、unnamed与八元素
Tuple types and conversions
Tuple conversion要求相同arity,并对每个position存在相应implicit或explicit conversion。Names不决定conversion identity:(int x, string y)可赋给(long id, object value),因为int到long、string到object逐项成立。Literal name与target name不一致可能得到warning,但值按position移动。
(int count, float ratio) source = (3, 0.5f);
(long count, double ratio) target = source;
(int left, int right) pair = (right: 1, left: 2); // names warn; positions still winAssignment与deconstruction都要关注evaluation order和position。Names相同也不会修正顺序错误。Tuple equality在支持它的后续C#版本中也是element-wise,names不参与;第四版的C# 7语境应先掌握conversion与representation,再把后续语法标成versioned update。
↡tuple element name通过编译器与metadata辅助source consumers,但不成为ValueTuple value的runtime identity。切换same types、numeric、name与arity cases
Tuples in the CLR
Tuple语法由compiler映射到generic ValueTuple structs。Arity二到七有对应generic forms,更长tuples通过第八个Rest继续nesting。Element names可由attributes在某些metadata positions保存供tools/consumers还原,但runtime generic type arguments不因id改成orderId而成为新type。
ValueTuple是value type,assignment会copy fields;fields本身是public且可变。若tuple含reference,copy只复制reference,不deep clone object。Boxing、interface dispatch、大tuple copy和nested Rest都可能影响hot path,先measure再优化。
↡从C# tuple syntax穿过assembly、reflection、serializer或language boundary后仍需明确的runtime形状规则。Alternatives to tuples
Anonymous type有named read-only properties和compiler-generated nominal-ish local type,但不能方便地作为public return type。KeyValuePair表达key/value,不能泛化为任意二元领域关系。Dedicated class/struct表达稳定business concept,可加入validation、methods、docs和serialization attributes;代价是额外声明。
C# 9 records是本书第四版之后的语言特性,不属于本章原始知识结构。它们可作为现代nominal data type候选,但不能反向把第四版Chapter 11改写成“records and tuples”。学习时先完整掌握本章的tuple composition与CLR model,再在版本边界外比较现代选择。
Uses and recommendations
判断标准是change ownership。Private method和caller一起修改时,tuple低成本且清晰;public API、stored schema、message contract或跨团队boundary需要稳定identity时,dedicated type更可靠。即使private tuple,超过三四项、同type positions很多或需要invariant时,也应升级为nominal type。
private static (decimal subtotal, decimal tax) Calculate(Order order) =>
(order.Lines.Sum(line => line.Total), order.Tax);
public sealed class InvoiceTotals
{
public decimal Subtotal { get; init; }
public decimal Tax { get; init; }
}切换private、public、key与domain value
本章回顾:把Position、Name、Representation和Ownership分开
- Tuple是fixed-arity heterogeneous composition,适合局部短生命周期shape。
- Literal与tuple type提供element names,但conversion与runtime identity仍以arity、position和types为核心。
- CLR层由ValueTuple structs与可能的Rest nesting表示,names通过额外metadata辅助tools。
- Tuple alternatives不是语法偏好,而是invariant、behavior与consumer ownership决策。
- 第四版本章讨论tuples;records属于后续版本补充,不能替换原目录。
练习
问题 1:为什么(string source, string destination)仍可能发生静默swap?
问题 2:一个private parser返回(bool success, int value, string error),何时应该升级类型?
问题 3:如何验收跨assembly public tuple改名?
术语表
名词解释
本章出现的专业名词,用大白话再讲一遍。
- nominal identity
- structural tuple shape
- tuple element name metadata
- representation boundary
- return-shape volatility
原版目录概念补充核对
以下条目补齐官方目录中容易被示例主线掩盖的概念。它们不重复罗列目录,而是明确每项概念的机制、适用边界和验收证据。
Tuple literals and tuple types:机制、边界与证据
Chapter 11. Composition using tuples中的Tuple literals and tuple types必须分清语言规范、编译器实现、运行时行为与基础类库 API 四层责任。固定 C# 语言版本和目标框架,用正向/负向编译案例、必要的 IL 或运行轨迹以及版本对照验证结论。
Tuple types and conversions:机制、边界与证据
Chapter 11. Composition using tuples中的Tuple types and conversions必须分清语言规范、编译器实现、运行时行为与基础类库 API 四层责任。固定 C# 语言版本和目标框架,用正向/负向编译案例、必要的 IL 或运行轨迹以及版本对照验证结论。
Tuples in the CLR:机制、边界与证据
Chapter 11. Composition using tuples中的Tuples in the CLR涉及值的存储位置、复制语义与生命周期,语法简洁不代表没有别名或逃逸限制。准备可编译和应被编译器拒绝的样本,结合 IL、分配计数或地址/修改轨迹核对复制、别名与边界。
Alternatives to tuples:机制、边界与证据
Chapter 11. Composition using tuples中的Alternatives to tuples必须分清语言规范、编译器实现、运行时行为与基础类库 API 四层责任。固定 C# 语言版本和目标框架,用正向/负向编译案例、必要的 IL 或运行轨迹以及版本对照验证结论。
Uses and recommendations:机制、边界与证据
Chapter 11. Composition using tuples中的Uses and recommendations必须分清语言规范、编译器实现、运行时行为与基础类库 API 四层责任。固定 C# 语言版本和目标框架,用正向/负向编译案例、必要的 IL 或运行轨迹以及版本对照验证结论。