【问题标题】:Linking a .NET Expression Tree into a new assembly将 .NET 表达式树链接到新程序集
【发布时间】:2009-10-24 18:24:03
【问题描述】:

我正在尝试编写自己的玩具 My Toy Language -> MSIL 编译器,以便更好地了解编译器的工作原理。我得到了解析和词法分析工作,我已经构建了表达式树并使用 System.Linq.Expressions 表达式树 API,我有一个工作解释器。现在我想发出一些真正的 MSIL 程序集。

问题是,我不知道如何实际构建这些程序集。 MethodBuilder 类只接受原始 MSIL 方法体,因此我必须获取表达式树的原始 MSIL。调用 Expression.Compile() 返回一个工作委托,但我无法获得其底层 MSIL。调用 MethodInfo.GetMethodBody() 会引发 InvalidOperationException,因为它没有在该特定子类中实现。

如何将该委托链接到新程序集?

【问题讨论】:

    标签: .net expression-trees cil reflection.emit


    【解决方案1】:

    刚刚找到。 LambdaExpression 的 DLR 版本公开了一个 CompileToMethod 方法,该方法完全符合我的需要。

    lambdaExpression.CompileToMethod(myMethodBuilder);
    

    【讨论】:

    • 请注意,此方法有一些限制,例如无法编译非静态方法。
    • @280Z28:幸运的是,我的玩具语言不是面向对象的,所以这不是问题。
    • 你能解释一下如何获得合适的MethodBuilder - 我知道这是很久以前的事了:)
    • 可以通过将实例作为第一个参数传递给命名方法来擦除面向对象
    【解决方案2】:

    为了发出原始 IL,您需要定义自己的 AST。您需要先获取 AssemblyBuilder,然后再获取 ModuleBuilder,然后您可以定义模块级方法或获取新的 TypeBuilder,现在获取 MethodBuilder 来定义类级方法。

    你说你已经有了词法分析器和解析器。这意味着您可以构建 AST。因此,只需遍历已解析的表达式并发出您的 IL。

    即使您获得(通过编译)生成的代码,您也无法用它做一些有用的事情,因为生成的代码依赖于基础架构。例如,如果您需要编译闭包,那么您应该创建类或其他存储词法变量等(例如需要在 .net 中使用异常的非词法控制转移)

    【讨论】:

    • 是的,这就是我要避免的。 LINQ 表达式树模型为我做了所有这些,所以我想使用它而不是编写自己的 MSIL 发射器。
    • 好的,您尝试学习编译器理论,但解析器和词法分析器是编译器中最少的部分。我们在 AST 和优化部分以及在发射器中拥有的所有乐趣 - 只是你尽量避免的事情
    • 有一本非常好的书,名为 Serge Lidin 的“Expert .NET 2.0 IL Assembler”,它将让您了解 MSIL 中的程序集结构。只要您了解基本的汇编程序概念,它就很容易阅读。我还建议使用 Mono.Cecil 作为库来发出你的 IL。我认为你会发现它比 Emit 命名空间下的库更容易使用。否则,我同意上述海报。如果你已经构建了 AST,你应该遍历每个语句并发出你的 IL。
    • 谢谢大家,但我不确定你是否理解我的问题。我已经有了抽象语法树。我知道如何编写 IL 发射器,我知道 MSIL,但我不想这样做,因为已经有一个 API。
    • 您“...为了更好地了解编译器的工作原理”。那么这些表达式(它们来自 Linq 和 DLR)不适用于编译器编写者。而且你必须自己编写编译器。它们旨在用于动态代码生成,因此实际上您拥有动态编译器而不仅仅是解释器。
    猜你喜欢
    • 2017-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多