表达式树

假设有这样一个类

public interface ILogger { }
public class UserService
{
    public UserService(ILogger logger) { /* ... */ }
}

我们想用表达式树"手搓"出一个委托,效果等同于:

Func<ILogger, UserService> factory = logger => new UserService(logger);
  1. 找到构造函数
var ctor = typeof(UserService).GetConstructor(new[] { typeof(ILogger) });
  • typeof(UserService) 拿到 UserService 的 Type 对象
  • GetConstructor(new[] { typeof(ILogger) }) 表示"找到参数列表为 (ILogger) 的那个构造函数(只要一个参数,参数为ILogger的构造函数)"
  • 结果 ctor 是一个 ConstructorInfo,即这个构造函数的元数据描述
    ctor 本身不能直接调用创建对象,它只是"关于构造函数的说明书"。
  1. 定义参数
var param = Expression.Parameter(typeof(ILogger), "logger");
  • 创建一个表达式树中的参数节点
  • 类型是 ILogger,名字叫 "logger"(名字只用于调试/ToString 显示,不影响执行)
  • 它代表未来这个 lambda 的入参
  • 对应到 logger => new UserService(logger) 里的 logger。

注意:这不是一个真实的变量,而是表达式树里的一个"占位符"节点。你可以在树的多个位置引用同一个 param 节点。

  1. 构建 new 表达式
var newExpr = Expression.New(ctor, param);
  • Expression.New 是工厂方法,用来构造"调用构造函数创建对象"的表达式节点
  • 第一个参数 ctor:要调用哪个构造函数
  • 后面是构造函数的实参列表,这里是 param(即上面的 logger)
  • 结果 newExpr 是一棵子树,描述 new UserService(logger)
    如果构造函数有多个参数,就继续在后面加:
Expression.New(ctor, param1, param2, param3);
  1. 包装成 Lambda
var lambda = Expression.Lambda<Func<ILogger, UserService>>(newExpr, param);
  • Expression.Lambda(body, params) 把 body 和参数组合成一个完整的 lambda 表达式树
  • 泛型参数 Func<ILogger, UserService> 指定这个 lambda 的签名:接收一个 ILogger,返回一个 UserService
  • newExpr 是 lambda 的主体
  • param 是 lambda 的参数
    == 至此得到的是一个 Expression<Func<ILogger, UserService>> 对象——它仍然只是数据,还不能执行。==
    用 lambda.ToString() 会看到类似:
logger => new UserService(logger)
  1. 编译成可执行委托
var factory = lambda.Compile();

-- Compile() 把表达式树编译成真实的 IL 代码,并返回一个可执行的委托
-- 返回类型是 Func<ILogger, UserService>(由第 4 行的泛型参数决定)
-- 编译后 factory 就是一个普通委托,调用它几乎无反射开销
==完全等价于直接写 Func<ILogger, UserService> factory = logger => new UserService(logger); ==

var ctor = typeof(UserService).GetConstructor(new[] { typeof(ILogger) });
var param = Expression.Parameter(typeof(ILogger), "logger");

var newExpr = Expression.New(ctor, param);
var lambda = Expression.Lambda<Func<ILogger, UserService>>(newExpr, param);
var factory = lambda.Compile();
posted @ 2026-09-10 15:09  是17阿哥呀  阅读(11)  评论(0)    收藏  举报