Lambda 到表达式树的转换

Posted

技术标签:

【中文标题】Lambda 到表达式树的转换【英文标题】:Lambda to Expression tree conversion 【发布时间】:2010-11-21 14:20:43 【问题描述】:

我会保持简单,

如何从 lambda 中获取表达式树??

还是来自查询表达式?

【问题讨论】:

【参考方案1】:

您必须将 lambda 分配给不同的类型:

// Gives you a delegate:
Func<int, int> f = x => x * 2;
// Gives you an expression tree:
Expression<Func<int, int>> g = x => x * 2;

方法参数也是如此。但是,一旦将这样的 lambda 表达式分配给 Func&lt;&gt; 类型,就无法取回表达式树。

【讨论】:

在第一种情况下,Delegate 是比 lambda 更好的术语。两者都是 lambda 表达式,一个隐式转换为匿名委托,另一个是表达式树。 @nawfal f 是代表。但是x =&gt; x * 2 是一个 lambda 表达式(正如您自己指出的那样)。你的评论暗示我说了一些不同的东西,但我真的没有。 你说第二个表达式给你一个表达式树。与此类似,第一个 lambda 表达式应该给你一个委托,而不是一个 lambda - 这是你的第一条评论。不吹毛求疵,只是提一下,以便将来对某人有所帮助。 @KonradRudolph,感谢您的提示。我想了解为什么x =&gt; x * 2 可以同时分配给Func&lt;int,int&gt;Expression&lt;Func&lt;int,int&gt;&gt;x =&gt; x * 2 的 CLR 类型是什么?这是否意味着Func&lt;int,int&gt;Expression&lt;Func&lt;int,int&gt;&gt; 派生自同一个基类型? @KFL,lambda 表达式本身是您作为程序代码键入的表达式,不一定对应于特定类型。 Func&lt;a, b&gt;Expression&lt;Func&lt;a, b&gt;&gt; 不必从相同的基类型派生,当您说 int x = 42float y = 42 时,intfloat 不必从相同的基类型派生【参考方案2】:

康拉德的回答是准确的。您需要将 lambda 表达式分配给 Expression&lt;Func&lt;...&gt;&gt;,以便编译器生成表达式树。如果你得到一个 Func&lt;...&gt;Action&lt;...&gt; 或其他委托类型的 lambda,那么你所拥有的只是一堆 IL 指令。

如果您确实需要能够将 IL 编译的 lambda 转换回表达式树,则必须对其进行反编译(例如,执行 Lutz Roeder 的 Reflector 工具所做的事情)。我建议您查看Cecil 库,它提供了高级 IL 操作支持,可以为您节省相当多的时间。

【讨论】:

【参考方案3】:

只是为了扩展 Konrad 的答案并纠正 Pierre,您仍然可以从 IL 编译的 lambda 生成表达式,尽管它不是非常优雅。扩充康拉德的例子:

// Gives you a lambda:
Func<int, int> f = x => x * 2;

// Gives you an expression tree:
Expression<Func<int, int>> g = x => f(x);

【讨论】:

给你原始lamda的表达式树,它给你一个调用委托的new表达式树。仅此而已。 这个问题并不特定于获得 equivalent 表达式。对于内存中的 LINQ,这提供了相同的功能。当然,任何 LINQ 提供程序都无法正确解析它。

以上是关于Lambda 到表达式树的转换的主要内容,如果未能解决你的问题,请参考以下文章

Lambda表达式树解析(下)

C# 表达式树 创建生成使用lambda转成表达式树~表达式树的知识详解

Lambda表达式树构建(上)

基于Expression Lambda表达式树的通用复杂动态查询构建器——《剧透一下》

基于Expression Lambda表达式树的通用复杂动态查询构建器——《构思篇二》已开源

表达式树的说明与运用