Lambda Expression Compile()方法有什么作用?

我试图在C#中理解AST。 我想知道,这个例子中的Compile()方法到底是做什么的。

 // Some code skipped Expression<Func> data = Expression.Lambda<Func>( Expression.Call(s, typeof(string).GetMethod(“Substring”, new Type[] { typeof(int), typeof(int) }), a, b), s, a, b ); Func fun = data.Compile(); 

为了防止误解,我理解Expression.LambdaExpression.Call构造。 我感兴趣的是Compile()方法。 它以某种方式产生真正的MSIL吗? 我能看到MSIL吗?

我感兴趣的是Compile()方法。 它以某种方式产生真正的MSIL吗?

是。 Compile方法在lambda body块上运行访问者,并为每个子表达式动态生成IL。

如果您有兴趣学习如何自己吐IL,请参阅如何使用Lightweight Codegen的“Hello World”示例 。 (我注意到,如果你处于一个部分受信任的应用程序域中必须使用Lightweight Codegen的不幸位置,那么在具有限制性跳过可见性的世界中,事情会变得有些奇怪;如果您感兴趣,请参阅Shawn Farkas关于该主题的文章 。)

我能看到MSIL吗?

是的,但你需要一个特殊的“可视化器”。 我在实现我的部分时用来调试Compile()的可视化工具可以在这里下载:

http://blogs.msdn.com/b/haibo_luo/archive/2005/10/25/484861.aspx

表达式表示表达式树forms的数据结构 – 使用Compile()这个表达式树可以以委托forms(这是一种“方法”调用)编译成可执行代码。

编译之后,您通常可以调用委托 – 在您的示例中,委托是Func 。 当您基于仅在运行时可用的数据动态创建表达式树时,可能需要此方法,其最终目标是创建和执行相应的委托。

您无法看到代表的“代码”。 它所基于的表达式树本身就是最接近它的。

对此的答案现在已经过时了,因为现在有时会发生什么。

向IL编译表达式需要Reflection.Emit,它始终不可用,特别是AOT。 因此,在这些情况下,不是编译到IL,而是将表达式“编译”为表示指令的对象列表。 这些指令中的每一个都有一个Run方法,它使得它执行适当的操作,处理一堆值,就像IL在堆栈上工作一样。 然后可以作为委托返回在这些对象上调用Run的方法。

通常运行这样的委托比运行IL慢,但它是唯一的选项,当编译到IL不可用时,编译步骤通常更快,所以编译+运行的总时间通常少于解释器而不是IL用于一次性表达。

出于这个原因,在.NET Core中,现在有一个Compile的重载,即使编译为IL可用,它也会采用布尔请求的解释。

所有这些都构成了有趣的语言组合; 表达式本身是一种语言,程序集用C#编写,它可以编译成IL,解释的指令对象构成第四种语言。