表达式树
假设有这样一个类
public interface ILogger { }
public class UserService
{
public UserService(ILogger logger) { /* ... */ }
}
我们想用表达式树"手搓"出一个委托,效果等同于:
Func<ILogger, UserService> factory = logger => new UserService(logger);
- 找到构造函数
var ctor = typeof(UserService).GetConstructor(new[] { typeof(ILogger) });
- typeof(UserService) 拿到 UserService 的 Type 对象
- GetConstructor(new[] { typeof(ILogger) }) 表示"找到参数列表为 (ILogger) 的那个构造函数(只要一个参数,参数为ILogger的构造函数)"
- 结果 ctor 是一个 ConstructorInfo,即这个构造函数的元数据描述
ctor 本身不能直接调用创建对象,它只是"关于构造函数的说明书"。
- 定义参数
var param = Expression.Parameter(typeof(ILogger), "logger");
- 创建一个表达式树中的参数节点
- 类型是 ILogger,名字叫 "logger"(名字只用于调试/ToString 显示,不影响执行)
- 它代表未来这个 lambda 的入参
- 对应到 logger => new UserService(logger) 里的 logger。
注意:这不是一个真实的变量,而是表达式树里的一个"占位符"节点。你可以在树的多个位置引用同一个 param 节点。
- 构建 new 表达式
var newExpr = Expression.New(ctor, param);
- Expression.New 是工厂方法,用来构造"调用构造函数创建对象"的表达式节点
- 第一个参数 ctor:要调用哪个构造函数
- 后面是构造函数的实参列表,这里是 param(即上面的 logger)
- 结果 newExpr 是一棵子树,描述 new UserService(logger)
如果构造函数有多个参数,就继续在后面加:
Expression.New(ctor, param1, param2, param3);
- 包装成 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)
- 编译成可执行委托
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();

浙公网安备 33010602011771号