Chapter 8. Super-sleek properties and expression-bodied members
覆盖property历史、C# 6 auto-property upgrades与expression-bodied members,区分storage、initialization、mutability、cost和API evolution。
学习目标
- 能比较manual、C# 3 auto、C# 6 getter-only与initializer property的storage、assignment和mutability规则
- 能分析method/property/indexer/operator的expression body,判断evaluation、side effect和failure是否适合单表达式
- 能设计public data、immutable reference、computed value与validated mutation的property contract并验证evolution
机制总览
Chapter 8. Super-sleek properties and expression-bodied members:机制路径
- 1
为什么Property语法越短,Contract反而要写得…
C 6让getter-only auto property与initializer消除大量backing-field ceremony,也让method/property可用expression body。一行code可更突出意图,但也更容易让reader误判“值已缓存”“对象深度不可变”或“get…
- 2
A brief history of properties
C 1 manual property以explicit field和accessor bodies封装storage;能validation、lazy compute、notify或virtual override,但trivial case重复。C 3 auto property让compile…
- 3
Upgrades to automatically imp…
C 6支持auto-property initializer,让common default在每条constructor path前建立;execution order与field initializers一起按declaration规则发生,base construction与derived in…
章级决策实验
Chapter 8. Super-sleek properties and expression-bodied members:机制与证据
切换《Chapter 8. Super-sleek properties and expression-bodied members》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。
选择推理阶段
当前阶段 · 为什么Property语法越短,Contract反而要写得…
C 6让getter-only auto property与initializer消除大量backing-field ceremony,也让method/property可用expression body。一行code可更突出意图,但也更容易让reader误判“值已缓存”“对象深度不可变”或“get…
可核验证据
以明确的 LangVersion 与目标框架构建「为什么Property语法越短,Contract反而要写得…」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
学完《Chapter 8. Super-sleek properties and expression-bodied members》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。
失效—证据矩阵
Chapter 8. Super-sleek properties and expression-bodied members:失效与核验
为什么Property语法越短,Contract反而要写得…
典型失效
若解释「为什么Property语法越短,Contract反而要写得…」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。
核验证据
以明确的 LangVersion 与目标框架构建「为什么Property语法越短,Contract反而要写得…」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
A brief history of properties
典型失效
若解释「A brief history of properties」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。
核验证据
以明确的 LangVersion 与目标框架构建「A brief history of properties」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
Upgrades to automatically imp…
典型失效
若解释「Upgrades to automatically imp…」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。
核验证据
以明确的 LangVersion 与目标框架构建「Upgrades to automatically imp…」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
为什么Property语法越短,Contract反而要写得越清楚
C# 6让getter-only auto property与initializer消除大量backing-field ceremony,也让method/property可用expression body。一行code可更突出意图,但也更容易让reader误判“值已缓存”“对象深度不可变”或“getter一定cheap”。语法只决定生成形式,不替API定义cost与mutation。
先预测:getter-only auto property引用的List是否immutable;property initializer是否在base constructor后执行;expression-bodied property是否只计算一次;所有one-line methods是否适合=>。答案都是否。
A brief history of properties
C# 1 manual property以explicit field和accessor bodies封装storage;能validation、lazy compute、notify或virtual override,但trivial case重复。C# 3 auto property让compiler生成field/accessors,保留property API与未来从source增加body的能力。
Public field与property在binary metadata/call semantics不同,后续把field换property可能破坏consumer;因此对外从property开始。Private field仍适合内部storage,不能把“property优先”机械扩展到每个local implementation detail。
private string _name;
public string Name
{
get => _name;
private set => _name = Validate(value);
}切换manual、auto、getter-only与initializer
Upgrades to automatically implemented properties
C# 6支持auto-property initializer,让common default在每条constructor path前建立;execution order与field initializers一起按declaration规则发生,base construction与derived initialization顺序仍需理解。Initializer若调用virtual/外部I/O或依赖尚未建立的state,会隐藏partial-construction风险。
Getter-only auto property可在declaration initializer或constructor中赋值,之后不能普通reassign,接近readonly field的reference assignment contract。它不冻结referenced object:IList<T>仍可mutation。Deep immutability需immutable type、copy或只读projection,并明确ownership。
Constructor-only assignment有助于object valid-before-publish,但deserializer/ORM需求可能要求private setter/init或factory。选择由framework boundary与domain invariant决定,不为tool convenience公开无约束set。
public sealed class Report
{
public string Name { get; }
public IReadOnlyList<Line> Lines { get; } = Array.Empty<Line>();
public Report(string name) => Name = Validate(name);
}Expression-bodied members
Expression-bodied method把单一return/void expression写在signature旁;property/indexer getter每次访问都evaluate expression;operator/conversion可清楚表达pure transformation。C# 6最初支持范围有限,后续版本扩展constructors、accessors等,应标明language version。
=>不保证pure、fast、nonthrowing或cached。一个property若发network request、allocate大collection或改变state,即使能写成一行也违反caller对property的常见cost直觉。把expensive/async/fallible operation做named method,让call site看见action。
Expression body适合一个abstraction level、一个obvious expression;需要guard、multiple steps、structured logging、try/finally或debug breakpoints时block更清晰。Conciseness是结果,不是目标函数。
切换method、property、indexer与operator
选择Property Form的Decision Matrix
Public data默认property以保留evolution;simple mutable state用auto get/set但先确认setter真的是合法public command;construction-only reference用getter-only;computed cheap value用getter expression;validation、notification或lazy cache用full property或domain method。
Property setter应保持快速、local和predictable。重大business transition、remote I/O或可能多种failure的operation用method,返回result/task并支持cancellation。Indexer同样应像collection access,不隐藏O(n) remote scan而无文档。
Modern version boundary
Modern init/required members能表达object-initializer construction contract,是C# 9/11 update,不属于原章C# 6。它们减少mutation window,但required只保证caller初始化语法,不自动validate non-null/domain validity;constructor/factory仍可更强。
public decimal Net => Gross - Tax; // cheap derived property
public Task RepriceAsync(CancellationToken token); // visible operation切换public、immutable、computed与validated场景
本章回顾:Sleek Syntax必须服务Stable Surface
- Property封装access contract;field、auto与manual是不同member/API形状。
- Getter-only限制reference reassignment,不保证referenced object深度immutable。
- Initializer建立common default,但仍受construction order与failure影响。
- Expression body每次evaluate,不承诺pure、cheap、cached或nonthrowing。
- Public member选择同时考虑mutability、cost、failure与future evolution,不以最短source决定。
练习
问题 1:getter-only List<T> property是否足够immutable?
问题 2:何时expression-bodied property应改成method?
问题 3:如何让多个constructors共享property default而不破坏invariant?
术语表
名词解释
本章出现的专业名词,用大白话再讲一遍。
- property surface contract
- shallow immutability boundary
- computed-access contract
- construction completeness
- member evolution budget