Chapter 15. C# 8 and beyond

以第四版2019年的preview视角覆盖nullable references、switch expressions、recursive patterns、indexes/ranges、async streams/disposal及参与语言演进的方法。

学习目标

  • 能解释nullable reference annotations与flow analysis如何表达null intent,区分warning、suppression、runtime validation和migration context
  • 能推导switch expression、recursive patterns、Index与Range的match/bounds结果,并设计exhaustiveness和slice-cost tests
  • 能设计async stream与async disposal的producer-consumer protocol,复现iteration、early exit、cancellation、failure和cleanup路径

机制总览

Chapter 15. C# 8 and beyond:机制路径

  1. 1

    为什么必须同时保留Preview历史与最终Version边界

    第四版在2019年出版,本章面对的是C 8尚在形成中的language。它不仅介绍syntax,也示范如何读proposal、试preview compiler、区分design intent与shipping guarantee。今天回看时要做双层叙述:先还原书中看到的候选方向,再标明后来C 8落地的稳定语义;不能把更晚版本的扩展伪装成作者当时已知结论。

  2. 2

    Nullable reference types

    Nullable reference types为reference values增加compile-time intent:在enabled context中, string 表示正常path期望non-null, string?

  3. 3

    Switch expressions

    Switch expression把input映射为一个result,arms通常以pattern、optional guard和expression组成。它比statement更适合pure classification,促使每个arm产生同一target-compatible result。Ar…

先按顺序建立机制,再进入实验切换阶段并检查失效证据。

章级决策实验

Chapter 15. C# 8 and beyond:机制与证据

切换《Chapter 15. C# 8 and beyond》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。

选择推理阶段

当前阶段 · 为什么必须同时保留Preview历史与最终Version边界

第四版在2019年出版,本章面对的是C 8尚在形成中的language。它不仅介绍syntax,也示范如何读proposal、试preview compiler、区分design intent与shipping guarantee。今天回看时要做双层叙述:先还原书中看到的候选方向,再标明后来C 8落地的稳定语义;不能把更晚版本的扩展伪装成作者当时已知结论。

可核验证据

以明确的 LangVersion 与目标框架构建「为什么必须同时保留Preview历史与最终Version边界」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。

学完《Chapter 15. C# 8 and beyond》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。

失效—证据矩阵

Chapter 15. C# 8 and beyond:失效与核验

为什么必须同时保留Preview历史与最终Version边界

典型失效

若解释「为什么必须同时保留Preview历史与最终Version边界」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。

核验证据

以明确的 LangVersion 与目标框架构建「为什么必须同时保留Preview历史与最终Version边界」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。

Nullable reference types

典型失效

若解释「Nullable reference types」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。

核验证据

以明确的 LangVersion 与目标框架构建「Nullable reference types」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。

Switch expressions

典型失效

若解释「Switch expressions」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。

核验证据

以明确的 LangVersion 与目标框架构建「Switch expressions」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。

每个判断都必须能落到观测、测试或产物,不能只凭代码表面推测。

为什么必须同时保留Preview历史与最终Version边界

第四版在2019年出版,本章面对的是C# 8尚在形成中的language。它不仅介绍syntax,也示范如何读proposal、试preview compiler、区分design intent与shipping guarantee。今天回看时要做双层叙述:先还原书中看到的候选方向,再标明后来C# 8落地的稳定语义;不能把更晚版本的扩展伪装成作者当时已知结论。

先预测:string?是否创建新的CLR runtime type;!是否插入runtime null check;switch expression是否天然处理所有未来subtypes;^1是否等于length-1这个数值而不依赖receiver;range slicing是否总为零allocation;停止await foreach是否自动取消所有producer work。答案都需要contract和target-type context,而不是只背符号。

Nullable reference types

Nullable reference types为reference values增加compile-time intent:在enabled context中,string表示正常path期望non-null,string?表示null是允许state。它不改变CLR中reference可为null的事实,也不会让string成为全新runtime type;价值来自annotations、warnings和flow analysis共同暴露潜在contract mismatch。

Flow state会因null check、patterns、assignment、member annotations和method contracts变化。Migration应按boundary推进:先启用warnings观察legacy oblivious code,再标annotated API,修真正fault,最后才对有外部证明的点使用suppression。value!只告诉compiler暂信此处non-null,runtime value完全不变。

#nullable enable
static int LengthOrZero(string? text)
{
    if (text is null) return 0;
    return text.Length; // flow state is non-null here
}
分步1 / 3

切换non-null、maybe-null、oblivious与suppressed

Switch expressions

Switch expression把input映射为一个result,arms通常以pattern、optional guard和expression组成。它比statement更适合pure classification,促使每个arm产生同一target-compatible result。Arm order仍重要,missing case需要明确处理;对enum或closed hierarchy可用tests/analysis逼近exhaustiveness,对open world必须保留unknown policy。

static decimal Discount(Customer customer) => customer switch
{
    { IsVip: true, Years: >= 5 } => 0.20m,
    { IsVip: true } => 0.10m,
    null => throw new ArgumentNullException(nameof(customer)),
    _ => 0m,
};

Recursive pattern matching

Recursive patterns允许在一个pattern中继续检查properties、positions与nested shapes,把“type + fields + guards”写成declarative classifier。C# 8的property/positional patterns建立在Chapter 12的test-and-bind model上;后续版本又加入relational、logical、list等patterns,必须另标版本,不能塞回原书preview。

Pattern读取property可能执行getter并抛异常或产生cost,不能假设它只是field match。Overlapping arms按order解决;复杂business classification应配decision table,若pattern树比domain language更难读,就抽出named predicates或domain methods。

Indexes and ranges

Index表达从start或end定位,^1通常表示last element;Rangestart..end表达start-inclusive、end-exclusive interval。语法由receiver支持的indexer/Length/Count与Slice patterns解释,因此bounds、empty range和copy/view semantics取决于target type。

Array/string slicing常产生新array/string;Span slicing通常产生view。不要从[..]符号推断allocation-free。Off-by-one tests应覆盖empty、single、full、from-end、start=end、reversed与out-of-range,并明确Unicode string slicing按UTF-16 code units而非grapheme clusters。

分步1 / 3

切换switch、property pattern、index与range

More async integration

C# 8把async扩展到iteration与cleanup。IAsyncEnumerable<T>配合await foreach让每次MoveNext可异步等待,适合streaming I/O;IAsyncDisposable配合await using让cleanup本身可异步完成。它们不是把普通collection/Dispose加一个await,而是新的producer-consumer protocols。

await foreach (Order order in repository.StreamAsync(cancellationToken))
{
    await ProcessAsync(order, cancellationToken);
}
 
await using var lease = await pool.AcquireAsync(cancellationToken);

Early break、consumer exception、cancellation和enumerator failure都必须走cleanup policy。Cancellation token如何传给async iterator取决于method/consumer contract;停止enumeration不一定终止producer已启动的independent work。Backpressure也不是自动无限安全,producer每次yield和buffering strategy要审计。

分步1 / 3

切换async stream、dispose、cancellation与failure

Features not yet in preview

原书把“尚未进入preview”的候选特性单独讨论,核心方法比名单更重要:proposal可能被推迟、重塑、拆分或取消;syntax、runtime support、BCL support和tooling maturity也可能不同步。教材应保存当时状态,不把后来结果倒写成必然。

阅读历史proposal时给每项加四列:book-time status、first shipping version、current semantics、required runtime/library。这样既尊重原书,也让现代reader不把preview sample直接复制到production。

Getting involved

C#设计过程公开在language proposals、notes、compiler preview与issue discussions中。有效参与不是只投票喜欢某个syntax,而是提交最小use case、alternative、compatibility constraints、lowering/runtime cost和可复现compiler feedback。先验证已有proposal是否覆盖问题,再用小project测试LangVersion和target framework。

参与也要区分language、compiler、runtime与library repositories。一个feature无法工作时,先缩小是parser/type checker、generated IL、runtime capability还是BCL API缺口;清晰的层次证据比宽泛意见更能推动设计。

本章回顾:Preview阅读能力也是语言能力

  1. Nullable references增加annotation和flow analysis,不改变CLR null,也不替代runtime validation。
  2. Switch expressions与recursive patterns压缩classification,但仍依赖order、coverage和getter semantics。
  3. Index/Range表达bounds,allocation与view由target type决定。
  4. Async streams/disposal扩展了iteration与cleanup protocols,cancellation和failure ownership必须测试。
  5. Preview、shipping与modern extension要分层记录;参与设计需要可复现use case和跨层证据。

练习

问题 1:一个legacy library启用nullable后出现五千warnings,怎样迁移?

问题 2:Range API如何证明既正确又没有错误的性能假设?

问题 3:Async stream在consumer处理第3项失败时怎样闭环?

术语表

名词解释

本章出现的专业名词,用大白话再讲一遍。

nullable flow state
exhaustiveness policy
recursive shape match
slice boundary contract
asynchronous iteration protocol
asynchronous cleanup ownership

原版目录概念补充核对

以下条目补齐官方目录中容易被示例主线掩盖的概念。它们不重复罗列目录,而是明确每项概念的机制、适用边界和验收证据。

Recursive pattern matching:机制、边界与证据

Chapter 15. C# 8 and beyond中的Recursive pattern matching涉及值的存储位置、复制语义与生命周期,语法简洁不代表没有别名或逃逸限制。准备可编译和应被编译器拒绝的样本,结合 IL、分配计数或地址/修改轨迹核对复制、别名与边界。

Indexes and ranges:机制、边界与证据

Chapter 15. C# 8 and beyond中的Indexes and ranges必须分清语言规范、编译器实现、运行时行为与基础类库 API 四层责任。固定 C# 语言版本和目标框架,用正向/负向编译案例、必要的 IL 或运行轨迹以及版本对照验证结论。

More async integration:机制、边界与证据

Chapter 15. C# 8 and beyond中的More async integration涉及值的存储位置、复制语义与生命周期,语法简洁不代表没有别名或逃逸限制。准备可编译和应被编译器拒绝的样本,结合 IL、分配计数或地址/修改轨迹核对复制、别名与边界。

Features not yet in preview:机制、边界与证据

Chapter 15. C# 8 and beyond中的Features not yet in preview涉及值的存储位置、复制语义与生命周期,语法简洁不代表没有别名或逃逸限制。准备可编译和应被编译器拒绝的样本,结合 IL、分配计数或地址/修改轨迹核对复制、别名与边界。

Getting involved:机制、边界与证据

Chapter 15. C# 8 and beyond中的Getting involved涉及值的存储位置、复制语义与生命周期,语法简洁不代表没有别名或逃逸限制。准备可编译和应被编译器拒绝的样本,结合 IL、分配计数或地址/修改轨迹核对复制、别名与边界。

资料与写作方式声明

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

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

讨论

评论区加载中…