0Pricing
C# Academy · 课时

LINQ 提供程序中的表达式树

了解提供程序如何将表达式转换为查询。

LINQ 提供程序中的表达式树 是 CoddyKit 上的免费 C# Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

LINQ 为什么需要表达式树

LINQ 有两种形式。IEnumerable<T>会在内存中运行 Lambda。IQueryable<T>则会以表达式树的形式接收 Lambda,使提供程序能够将其转换为另一种语言,例如 SQL。

可枚举序列与可查询序列

区别在于参数类型:IEnumerable.Where接收Func<T,bool>(已编译的委托),而IQueryable.Where接收Expression<Func<T,bool>>(表达式树)。

using System;
using System.Linq;
using System.Linq.Expressions;

int[] nums = { 1, 2, 3, 4 };
// IEnumerable path: lambda is a compiled delegate
var evens = nums.Where(n => n % 2 == 0);
Console.WriteLine(string.Join(",", evens)); // 2,4

查询保持为数据

使用IQueryable时,您的 Lambda 会被捕获为表达式树,尚不会执行。提供程序会检查这棵树来构建查询。

using System;
using System.Linq;
using System.Linq.Expressions;

IQueryable<int> q = new[] { 1, 2, 3, 4, 5 }.AsQueryable();
var filtered = q.Where(n => n > 2);
Console.WriteLine(filtered.Expression.NodeType); // Call (a method-call tree)

检查查询表达式

可查询对象上的Expression属性会公开提供程序将要转换的表达式树。

using System;
using System.Linq;

var q = new[] { 10, 20, 30 }.AsQueryable().Where(x => x >= 20);
Console.WriteLine(q.Expression.ToString().Contains("Where")); // True

转换,而非执行

实体框架之类的提供程序会遍历表达式树,并生成类似WHERE Age > 18的 SQL。您的 C# 谓词不会在客户端运行;实际工作由数据库完成。

IQueryProvider 的作用

IQueryable包含一个IQueryProvider。当您枚举查询时,提供程序会接收表达式树,并决定如何执行查询。

using System;
using System.Linq;

var q = new[] { 1, 2, 3 }.AsQueryable();
Console.WriteLine(q.Provider.GetType().Name); // EnumerableQuery (the in-memory provider)

延迟执行

只有在您枚举查询时(例如调用ToList或使用foreach),表达式树才会被转换并运行。在此之前,它只是可以继续组合的纯数据。

using System;
using System.Linq;

var q = new[] { 1, 2, 3, 4 }.AsQueryable()
    .Where(n => n > 1)
    .Select(n => n * 10);
// nothing has run yet; now force it:
Console.WriteLine(string.Join(",", q.ToList())); // 20,30,40

组合查询

由于每个运算符都会向表达式树添加内容,您可以分阶段构建查询,而提供程序会在执行时看到完整的查询。

using System;
using System.Linq;

var baseQuery = new[] { 5, 15, 25, 35 }.AsQueryable();
var q = baseQuery.Where(n => n > 10);
q = q.Where(n => n < 30); // composed: 10 < n < 30
Console.WriteLine(string.Join(",", q.ToList())); // 15,25

无法转换的内容

提供程序只能转换自己理解的操作。调用任意 C# 方法的谓词可能会在执行时抛出异常,因为它没有对应的 SQL 表达。

编写您自己的提供程序

自定义提供程序实现IQueryProvider,并使用ExpressionVisitor遍历表达式树,将每个节点转换为目标查询语言。

综合运用

这里展示了关键概念:同一个 Lambda 对IEnumerable而言是委托,对IQueryable而言则是表达式树,因此可以进行转换。

using System;
using System.Linq;
using System.Linq.Expressions;

Expression<Func<int, bool>> predicate = n => n > 2;
var data = new[] { 1, 2, 3, 4 };
// IEnumerable needs a delegate:
Console.WriteLine(string.Join(",", data.Where(predicate.Compile()))); // 3,4
// IQueryable accepts the tree directly:
Console.WriteLine(string.Join(",", data.AsQueryable().Where(predicate))); // 3,4

快速检查

请确认表达式树在 LINQ 提供程序中所起的作用。

回顾

您已经学习了 LINQ 提供程序如何使用表达式树。

  • IEnumerable使用已编译的Func;IQueryable使用Expression<Func>表达式树。
  • 提供程序会转换表达式树(例如转换为 SQL),而不是运行它。
  • 执行会延迟到枚举时进行。
  • 只有可转换的操作才能工作;任意方法可能会失败。

常见问题解答

「LINQ 提供程序中的表达式树」课时是免费的吗?

是的 — 「LINQ 提供程序中的表达式树」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「LINQ 提供程序中的表达式树」这节课中我会学到什么?

了解提供程序如何将表达式转换为查询。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「LINQ 提供程序中的表达式树」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 什么是表达式树
  2. 手动构建表达式
  3. 编译和执行表达式
  4. LINQ 提供程序中的表达式树
← 返回 C# Academy