Chapter 2. C# 2

覆盖Generics、Nullable value types、Simplified delegate creation、Iterators与Minor features,解释compile-time contract和compiler-generated state。

学习目标

  • 能比较pre-generic object collection与generic type/method的compile-time、runtime representation和boxing差异
  • 能推导Nullable value types与Simplified delegate creation的conversion、default、capture和invocation语义
  • 能绘制iterator construction、MoveNext、Current与Dispose状态,复现partial enumeration的finally cleanup

机制总览

Chapter 2. C# 2:机制路径

  1. 1

    为什么C 2把Runtime猜测前移到Compiler C…

    C 1可以用 object 存任意值、手写delegate constructor、手写 IEnumerator ,但正确关系主要靠developer记忆和runtime cast。C 2的主线是把element type、absence、callable target和iteration stat…

  2. 2

    Generics

    Pre-generic ArrayList 只知道 object :value type插入要boxing,读取要cast,错误可能在很远的consumer处出现。

  3. 3

    Nullable value types

    Nullable 让non-nullable value type同时表达一个T或absence,syntax是 T?

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

章级决策实验

Chapter 2. C# 2:机制与证据

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

选择推理阶段

当前阶段 · 为什么C 2把Runtime猜测前移到Compiler C…

C 1可以用 object 存任意值、手写delegate constructor、手写 IEnumerator ,但正确关系主要靠developer记忆和runtime cast。C 2的主线是把element type、absence、callable target和iteration stat…

可核验证据

以明确的 LangVersion 与目标框架构建「为什么C 2把Runtime猜测前移到Compiler C…」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。

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

失效—证据矩阵

Chapter 2. C# 2:失效与核验

为什么C 2把Runtime猜测前移到Compiler C…

典型失效

若解释「为什么C 2把Runtime猜测前移到Compiler C…」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。

核验证据

以明确的 LangVersion 与目标框架构建「为什么C 2把Runtime猜测前移到Compiler C…」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。

Generics

典型失效

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

核验证据

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

Nullable value types

典型失效

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

核验证据

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

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

为什么C# 2把Runtime猜测前移到Compiler Contract

C# 1可以用object存任意值、手写delegate constructor、手写IEnumerator,但正确关系主要靠developer记忆和runtime cast。C# 2的主线是把element type、absence、callable target和iteration state交给compiler验证或生成,让错误更早、ceremony更少,同时保留可检查的runtime model。

先预测:List<string>是否是List<object>子类型;int? + int?只要一边有值是否就有值;调用iterator method是否立即执行body;anonymous method是否总不分配。答案都是否。

Generics

Pre-generic ArrayList只知道object:value type插入要boxing,读取要cast,错误可能在很远的consumer处出现。List<T>让add、indexer、enumerator都共享T,compiler能追踪关系;runtime也保留constructed generic type,不是Java式type erasure。

What can be generic?

Classes、structs、interfaces、delegates和methods都可generic。T属于instance state或多个members共同contract时用generic type;只参与一个operation时用generic method并让type inference减少call-site ceremony。Constraint不是documentation,而是compiler可调用哪些members的证明。

public static T Max<T>(T left, T right, IComparer<T> comparer) =>
    comparer.Compare(left, right) >= 0 ? left : right;

Runtime通常可为reference-type instantiations共享machine code,为value types生成specialized code以处理不同layout;具体策略是runtime实现细节。API correctness不能依赖“每个T一定一份code”,performance结论也必须profile。

分步1 / 3

切换object、generic、method与constraint

Nullable value types

Nullable<T>让non-nullable value type同时表达一个T或absence,syntax是T?HasValue区分状态,Value在empty时抛异常,GetValueOrDefault返回default但会丢失“真的为default”和“没有值”的区别。Domain API应保留absence直到有明确default policy的boundary。

Lifted operators把underlying operator提升到nullable operands。多数算术比较遇null产生null或false,但bool?&/|具有三值逻辑特例;不能凭“null传播”一句话推导全部。Nullable boxing也特殊:empty boxes为null,有值时box underlying T,而不是boxed Nullable<T>

int? quantity = null;
int? doubled = quantity * 2;       // null
object? boxed = quantity;          // null
object boxedValue = (int?)42;      // boxed Int32

Simplified delegate creation

C# 2允许method group conversion,省掉显式new Comparison<Product>(CompareProducts);overload resolution仍必须找到compatible target。Anonymous method把短callback body放在call site,并可capture外部variable storage,compiler通常生成hidden method和closure object。

Delegate是immutable invocation list。Combine/remove产生新delegate;multicast按顺序调用,非void只返回最后target结果,任一target抛异常会中断后续调用。Language simplification不定义thread safety、subscriber isolation或lifetime,这些由API contract补充。

分步1 / 3

切换nullable、method group、anonymous method与null delegate

Iterators

Iterator block包含yield return/yield break,compiler生成实现IEnumerable<T>/IEnumerator<T>的state machine。调用method通常只创建sequence object;body在MoveNext时执行,local state被提升为fields,Current暴露最近一次yield value。

每次可重复枚举的iterator应创建独立enumerator state;一个enumerator本身通常不可并发使用。Side effects、time、random和external source会在每次enumeration重跑,因此API要声明live sequence还是snapshot。

foreach通过try/finally确保enumerator Dispose。Iterator内部的try/finally会被lowering到state transitions;consumer提前break也应触发cleanup。yield return不能随意放入所有catch/finally组合,compiler restrictions正是为保持state-machine语义可实现。

public static IEnumerable<string> ReadLines(TextReader reader)
{
    string? line;
    while ((line = reader.ReadLine()) is not null)
        yield return line;
}
分步1 / 3

切换construction、MoveNext、Dispose与minor features

Minor features

Partial types允许generated与handwritten declarations合并为一个type,适合tool ownership boundary但不应按业务职责随意拆散;static classes让compiler禁止instance;namespace aliases解决name collision;different accessibility与fixed buffer等features各有特定场景。它们不像generics/iterator共享一条runtime机制,但都把意图从convention提升为language rule。

本章回顾:Type Relation和Control State都可由Compiler证明

  1. Generics保留T关系、减少cast/boxing,并以constraint表达可用能力。
  2. Nullable<T>把value absence纳入type,lifted operators与boxing有精确定义。
  3. Method group与anonymous method简化delegate creation,但capture和multicast lifetime仍需API定义。
  4. Iterator method call与body execution分离,MoveNext驱动generated state machine。
  5. Partial enumeration必须Dispose并运行finally;重复枚举是否重做work是公开contract。

练习

问题 1:为什么List&lt;Dog&gt;不能赋给List&lt;Animal&gt;,怎样提供安全只读view?

问题 2:nullable、delegate与closure三个null/lifetime问题如何区分?

问题 3:iterator读取resource时,谁应拥有resource?

术语表

名词解释

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

parameterized type contract
lifted operator
method group conversion
iterator state machine
partial enumeration contract

资料与写作方式声明

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

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

讨论

评论区加载中…