Chapter 3. C# 3: LINQ and everything that comes with it

覆盖Automatically implemented properties、Implicit typing、Initializers、Anonymous types、Lambda、Extension methods、Query expressions与LINQ整合。

学习目标

  • 能分析auto property、implicit local、initializer和anonymous type的compiler output、evaluation order与contract scope
  • 能比较lambda转换为delegate或expression tree,并判断extension/overload resolution选择的实际调用目标
  • 能推导query clauses到standard operator calls,复现Enumerable/Queryable与terminal execution差异

机制总览

Chapter 3. C# 3: LINQ and everything that comes with it:机制路径

  1. 1

    为什么C 3的许多小Feature最终汇聚成LINQ

    C 3不是只加入query syntax。Auto property让data carrier简洁, var 让anonymous type可命名于local scope,initializer让sample data易构建,lambda提供inline behavior,extension met…

  2. 2

    Automatically implemented pro…

    Auto property由compiler生成backing field与accessors,public contract仍是property。它适合没有额外validation的state;一旦需要invariant、computed value或observable mutation,就显式…

  3. 3

    Implicit typing

    var 要求initializer并在compile time得到exact static type;之后赋值和member resolution都按该type进行。它使anonymous type与复杂generic query可用,不等于 dynamic 。当右侧清楚揭示type时减少重复;当m…

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

章级决策实验

Chapter 3. C# 3: LINQ and everything that comes with it:机制与证据

切换《Chapter 3. C# 3: LINQ and everything that comes with it》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。

选择推理阶段

当前阶段 · 为什么C 3的许多小Feature最终汇聚成LINQ

C 3不是只加入query syntax。Auto property让data carrier简洁, var 让anonymous type可命名于local scope,initializer让sample data易构建,lambda提供inline behavior,extension met…

可核验证据

以明确的 LangVersion 与目标框架构建「为什么C 3的许多小Feature最终汇聚成LINQ」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。

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

失效—证据矩阵

Chapter 3. C# 3: LINQ and everything that comes with it:失效与核验

为什么C 3的许多小Feature最终汇聚成LINQ

典型失效

若解释「为什么C 3的许多小Feature最终汇聚成LINQ」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。

核验证据

以明确的 LangVersion 与目标框架构建「为什么C 3的许多小Feature最终汇聚成LINQ」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。

Automatically implemented pro…

典型失效

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

核验证据

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

Implicit typing

典型失效

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

核验证据

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

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

为什么C# 3的许多小Feature最终汇聚成LINQ

C# 3不是只加入query syntax。Auto property让data carrier简洁,var让anonymous type可命名于local scope,initializer让sample data易构建,lambda提供inline behavior,extension methods让operators看似属于source,expression tree让provider读取code structure。缺少任意一环,统一query experience都会更笨重。

先预测:var是否改变runtime type;object initializer是否绕过constructor;lambda是否天然是delegate;query expression是否由runtime解释。答案都是否。

Automatically implemented properties

Auto property由compiler生成backing field与accessors,public contract仍是property。它适合没有额外validation的state;一旦需要invariant、computed value或observable mutation,就显式实现accessor。Compiler-generated field name不是reflection/serialization的stable contract。

Property initializer与init/required等是后续版本演进,不能倒写成C# 3原始能力。现代代码可使用它们,但应区分“原书解释auto property”与“当前API选择immutability”。

Implicit typing

var要求initializer并在compile time得到exact static type;之后赋值和member resolution都按该type进行。它使anonymous type与复杂generic query可用,不等于dynamic。当右侧清楚揭示type时减少重复;当method name隐藏precision或abstraction时显式type更好。

Object and collection initializers

Object initializer先调用constructor,再按source order调用setters/field assignments;collection initializer翻译为一系列Add calls。若中途setter/Add抛异常,对象可能已经产生side effects但expression未返回。Constructor仍应建立最低valid invariant,initializer不是required-state验证的替代。

var order = new Order("A-42")
{
    Customer = customer,
    Priority = Priority.High,
};

Anonymous types

Anonymous type提供compiler-generated immutable properties、structural equality与useful ToString,适合local projection/composite key。Its identity受property names、types与order影响,不能在public signature中直接命名,也不应跨assembly当wire contract。需要长期domain meaning时提升为named record/class。

分步1 / 3

切换property、var、initializer与anonymous type

Lambda expressions

Lambda没有独立runtime type;它必须转换到compatible delegate或expression-tree target。Delegate路径生成可执行method并可能生成closure,expression path构建描述parameters、operations与calls的object graph。Provider只能翻译其理解的nodes,不能执行任意C#。

Overload resolution会根据candidate target types尝试lambda conversion,因此相同text在不同call site得到不同meaning。Statement lambda通常不能直接成为expression tree;optional/ref等signature也受版本规则限制。遇到ambiguity时显式声明target type比cast result更清楚。

Extension methods

Extension method是带this首参数的static method,并由using namespace与receiver static type参与compile-time resolution。Instance member优先,extension没有virtual dispatch,也不能访问private state。它让source.Where(...)形成fluent vocabulary,但真正调用仍是Enumerable.Where(source, ...)Queryable.Where(...)

Func<Order, bool> local = order => order.Total > 100m;
Expression<Func<Order, bool>> remote = order => order.Total > 100m;
分步1 / 3

切换delegate、expression、extension与overload

Query expressions

Query expression是compiler translation syntax。from/where/select映射到SelectManyWhereSelect等method calls;transparent identifiers帮助多from/let保留range variables。Translation发生在compile time,不是SQL parser嵌入C#。

Query syntax在join、group、continuation等relational shape上常更清楚;method syntax对短pipeline或无query-clause对应的operators更直接。二者可混用,选择可读性而非performance myth,因为最终operator chain才决定behavior。

The end result: LINQ

LINQ统一operators与lambda/query composition,不统一data source。IEnumerable<T>接收delegates并在process内enumerate;IQueryable<T>接收expression trees并让provider翻译。Deferred/eager、ordering、null semantics、string comparison与supported methods都由operator/provider contract决定。

var query =
    from order in orders
    where order.Total > minimum
    orderby order.CreatedAt
    select new { order.Id, order.Total };
分步1 / 3

切换where、select、join/group与完整LINQ

本章回顾:LINQ是Feature Convergence而非单一语法

  1. Auto property、var、initializer与anonymous type共同降低data shaping ceremony。
  2. var保留exact static type;initializer仍在constructor之后按顺序mutation。
  3. Lambda由target type决定delegate或expression tree,capture与translation contract不同。
  4. Extension按compile-time static resolution,instance member优先且没有virtual dispatch。
  5. Query expression映射到methods;Enumerable/Queryable与terminal决定执行引擎、时机和成本。

练习

问题 1:为何anonymous type、var与LINQ projection常一起出现?

问题 2:同一lambda传给List和EF query,为何测试策略不同?

问题 3:如何判断query syntax与method syntax的选择没有改变行为?

术语表

名词解释

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

feature convergence
anonymous structural shape
target-typed lambda conversion
extension binding
query expression translation

原版目录概念补充核对

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

Object and collection initializers:机制、边界与证据

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

Lambda expressions:机制、边界与证据

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

The end result: LINQ:机制、边界与证据

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

讨论

评论区加载中…