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. 1

    为什么Tuple适合临时组合而不是自动替代领域模型

    方法经常需要返回两个相关结果,LINQ pipeline也会临时携带value与index。C 7 tuples让这种composition有静态types和可读element names,不必为每个局部shape声明class。它的力量来自低ceremony,也因此缺少nominal type可以…

  2. 2

    Introduction to tuples

    Tuple表示固定长度、按position排列的heterogeneous values。与 System.Tuple reference types相比,C 7语法通常映射到 System.ValueTuple value types,并允许source层的element names。它适合pri…

  3. 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}");
分步1 / 3

切换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 win

Assignment与deconstruction都要关注evaluation order和position。Names相同也不会修正顺序错误。Tuple equality在支持它的后续C#版本中也是element-wise,names不参与;第四版的C# 7语境应先掌握conversion与representation,再把后续语法标成versioned update。

分步1 / 3

切换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再优化。

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; }
}
分步1 / 3

切换private、public、key与domain value

本章回顾:把Position、Name、Representation和Ownership分开

  1. Tuple是fixed-arity heterogeneous composition,适合局部短生命周期shape。
  2. Literal与tuple type提供element names,但conversion与runtime identity仍以arity、position和types为核心。
  3. CLR层由ValueTuple structs与可能的Rest nesting表示,names通过额外metadata辅助tools。
  4. Tuple alternatives不是语法偏好,而是invariant、behavior与consumer ownership决策。
  5. 第四版本章讨论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 或运行轨迹以及版本对照验证结论。

资料与写作方式声明

本章以C# in Depth, Fourth Edition, Chapter 11: Composition using tuples权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…