0Pricing
C# Academy · 课时

编译和执行表达式

将表达式树转换为可运行的委托。

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

从表达式树到委托

表达式树在您编译之前只是数据。Expression<TDelegate>.Compile()会将表达式树转换为可以调用的真正委托。

using System;
using System.Linq.Expressions;

Expression<Func<int, int>> tree = x => x + 1;
Func<int, int> fn = tree.Compile();
Console.WriteLine(fn(5)); // 6

编译手动构建的表达式树

您手动构建的表达式树也可以用相同方式编译,从而生成可正常工作的委托。

using System;
using System.Linq.Expressions;

var x = Expression.Parameter(typeof(int), "x");
var body = Expression.Multiply(x, Expression.Constant(3));
var lambda = Expression.Lambda<Func<int, int>>(body, x);
var fn = lambda.Compile();
Console.WriteLine(fn(4)); // 12

调用结果

编译后的委托与其他委托一样:可以调用、存储和传递。

using System;
using System.Linq.Expressions;

Expression<Func<int, int, int>> addExpr = (a, b) => a + b;
var add = addExpr.Compile();
Console.WriteLine(add(2, 3)); // 5
Console.WriteLine(add(10, 20)); // 30

Compile 并非没有代价

编译会产生运行时开销,因此应缓存生成的委托并重复使用,而不要在每次调用时都重新编译。

using System;
using System.Linq.Expressions;

Expression<Func<int, int>> tree = x => x * x;
var square = tree.Compile(); // compile once
for (int i = 1; i <= 3; i++)
    Console.Write(square(i) + " "); // 1 4 9
Console.WriteLine();

动态构建谓词

一种常见用法是在运行时根据用户 input 构建筛选谓词,然后将其编译为Func。

using System;
using System.Linq.Expressions;

var n = Expression.Parameter(typeof(int), "n");
var isPositive = Expression.GreaterThan(n, Expression.Constant(0));
var pred = Expression.Lambda<Func<int, bool>>(isPositive, n).Compile();
Console.WriteLine(pred(5));  // True
Console.WriteLine(pred(-2)); // False

组合条件

请使用Expression.AndAlso / OrElse在编译前组合谓词。

using System;
using System.Linq.Expressions;

var n = Expression.Parameter(typeof(int), "n");
var inRange = Expression.AndAlso(
    Expression.GreaterThanOrEqual(n, Expression.Constant(1)),
    Expression.LessThanOrEqual(n, Expression.Constant(10)));
var fn = Expression.Lambda<Func<int, bool>>(inRange, n).Compile();
Console.WriteLine(fn(5) + " " + fn(11)); // True False

编译计算过程

您可以在运行时组装算术公式,这对规则引擎和计算器很有用。

using System;
using System.Linq.Expressions;

var p = Expression.Parameter(typeof(double), "p");
// price * 1.2 (add 20% tax)
var withTax = Expression.Multiply(p, Expression.Constant(1.2));
var calc = Expression.Lambda<Func<double, double>>(withTax, p).Compile();
Console.WriteLine(calc(100)); // 120

使用 DynamicInvoke 调用无类型 Lambda

如果您使用了非泛型的Expression.Lambda,请将其编译为Delegate,然后调用DynamicInvoke。

using System;
using System.Linq.Expressions;

var x = Expression.Parameter(typeof(int), "x");
var body = Expression.Add(x, Expression.Constant(10));
Delegate d = Expression.Lambda(body, x).Compile();
Console.WriteLine(d.DynamicInvoke(5)); // 15

性能提示

一次性编译后,编译后的表达式运行速度大致相当于委托。对于高频执行路径,请在启动时编译一次并保存该委托。

using System;
using System.Linq.Expressions;

Expression<Func<int, int>> tree = x => x + x;
var doubler = tree.Compile();
int total = 0;
for (int i = 0; i < 5; i++) total += doubler(i);
Console.WriteLine(total); // 0+2+4+6+8 = 20

错误会在编译时显现

如果表达式树格式错误(例如缺少参数),Compile()会抛出异常,因此请先验证表达式树,再依赖它们运行。

using System;
using System.Linq.Expressions;

var x = Expression.Parameter(typeof(int), "x");
var y = Expression.Parameter(typeof(int), "y");
try {
    // body references y but lambda only declares x
    var lambda = Expression.Lambda<Func<int, int>>(Expression.Add(x, y), x);
    lambda.Compile();
} catch (InvalidOperationException) {
    Console.WriteLine("unbound parameter");
}

综合运用

在一个流程中构建、编译并运行一个小型公式。

using System;
using System.Linq.Expressions;

var x = Expression.Parameter(typeof(int), "x");
var formula = Expression.Add(
    Expression.Multiply(x, Expression.Constant(2)),
    Expression.Constant(3)); // 2x + 3
var fn = Expression.Lambda<Func<int, int>>(formula, x).Compile();
Console.WriteLine(fn(4)); // 11

快速检查

请确认如何执行表达式树。

回顾

您已经学习了如何编译和执行表达式树。

  • Compile()会将表达式树转换为可调用的委托。
  • 请缓存委托;编译只需承担一次性成本。
  • 您可以动态构建谓词和公式,然后进行编译。
  • 格式错误的表达式树会在Compile()处抛出异常。

常见问题解答

「编译和执行表达式」课时是免费的吗?

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

「编译和执行表达式」这节课中我会学到什么?

将表达式树转换为可运行的委托。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

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

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

「编译和执行表达式」课时需要多长时间?

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

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

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

此课程中的所有课时

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