Lambda表达式转换为表达式树

49

我会简单明了地回答,

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

或从查询表达式中获取?

4个回答

68

您必须将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<> 类型,你就无法获取表达式树了。


3
在这种情况下,“委托”是比“lambda表达式”更好的术语。两者都是lambda表达式,其中一个被隐式转换为匿名委托,另一个则是表达式树。 - nawfal
@nawfal f 是一个委托。但是 x => x * 2 是一个 lambda 表达式(正如你自己所指出的)。你的评论暗示我说了不同的话,但实际上我并没有。 - Konrad Rudolph
1
你说第二个表达式给了你一个表达式树。类比于此,第一个lambda表达式应该给你一个委托,而不是一个lambda - 这就是你的第一个评论所说的。不是吹毛求疵,只是提醒以后有人可以受益。 - nawfal
1
@KonradRudolph,感谢您的提示。我想了解为什么x => x * 2既可以分配给Func<int,int>又可以分配给Expression<Func<int,int>>x => x * 2的CLR类型是什么?这是否意味着Func<int,int>Expression<Func<int,int>>派生自相同的基类型? - KFL
2
@KFL,lambda表达式本身就是您键入的程序代码表达式,不一定对应于特定类型。 “Func < a,b>”和“Expression < Func < a,b>>”不必派生自相同的基类型,就像当您说“int x = 42”和“float y = 42”时,“int”和“float”不派生自相同的基类型一样。 - ohw
显示剩余2条评论

11
Konrad的回答是准确的。您需要将lambda表达式分配给Expression<Func<...>>,以便编译器生成表达式树。如果您获得lambda作为Func<...>Action<...>或其他委托类型,则只有一堆IL指令。
如果您真的需要能够将已编译的IL lambda转换回表达式树,则必须对其进行反编译(例如执行Lutz Roeder的Reflector工具所做的操作)。我建议看看Cecil库,它提供了高级IL操作支持,并可以节省您很多时间。

8

进一步完善Konrad的回答并纠正Pierre的错误,尽管它不太优雅,但仍然可以从编译成IL的lambda生成表达式。扩展Konrad的示例:

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

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

17
这并不会给你原始lambda表达式的表达式树,而是给你一个调用委托的新的表达式树。仅此而已。 - Aidiakapi
这个问题并不特别关注获取一个等效的表达式。对于内存中的LINQ,这提供了完全相同的功能。当然,它可能无法被任何LINQ提供程序正确解析。 - joniba

0
一个运行时的替代方案是使用这个项目 - https://github.com/kostat/XLinq

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接