8

在 .NET 2.0-3.5 框架中,LCG(又名 DynamicMethod 类)是一种在运行时发出轻量级方法的好方法,而无需类结构来支持它们。

在 .NET 4.0 中,表达式树现在支持语句和块,因此似乎提供了足够的功能来构建您可能需要从这种方法中获得的任何功能,并且可以以比直接发出 CIL 更容易和更安全的方式构建操作码。(此声明源自今天将一些最复杂的 LCG 代码转换为使用表达式树构建和编译的实验。)

那么有什么理由可以在任何新代码中使用 LCG 吗?有什么表达树不能做的事情吗?或者它现在是一个“死”的功能?

4

4 回答 4

3

没有任何中间步骤直接构建 CIL 是没有意义的。但是使用你自己的最终以 IL 为目标的中间语言是完全可以的。表达式树等是不够的——它只是一种语言,而在实现 DSL 时,您需要许多不同的语义。

您可以轻松发出不安全的代码(有很多 ldftns 等),可以发出尾调用(不确定是否可以使用表达式),对虚拟方法的非虚拟调用,您可以有效地构造带有标签和跳转的大型状态自动机等. 表达式树是如此有限,以至于我根本无法理解如何将它们与原始 CIL 进行比较。

于 2011-04-12T20:11:03.067 回答
1

表达式树无疑是大多数运行时生成的代码的一种方式。但是,您应该清楚地意识到它是有限的,并且不能让您访问 MSIL 语言的全部功能。所以 LGC 和 ILGenerator 肯定会留下来完成要求更高的任务。

于 2014-11-19T20:21:25.170 回答
1

好吧,这个问题现在已经很老了,我正在等待tf get完成......所以我会自己回答。

是的,LCG 在大多数情况下都死了。

我们过去经常使用 LCG,现在它已经全部转换为使用表达式树。它们更容易构建,代码更容易维护和调试,并且当您在开发过程中出错时,错误消息通常比“操作可能破坏运行时稳定”提供更多信息。

但是,也许最重要的是,表达式树是可以组合的,而 Reflection.Emit 不是。这意味着用于运行时代码生成的组件架构可以更加模块化,甚至允许插件扩展代码生成框架。

我发现 Reflection.Emit 支持但表达式树不直接支持的一件事是设置.initonly字段。然而,这可以通过使用一个小助手类并在表达式树中调用它来实现,例如我使用的如下:

internal static class FieldHelper
{
    public static TTarget AssignInitOnlyField<TTarget, TField>(
        TTarget target, string fieldName, TField value)
    {
        var field = target.GetType().GetField(
            fieldName, 
            BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
        var boxed = (object)target; // required for value type support
        field.SetValue(boxed, value);
        return (TTarget)boxed;
    }
}

值得一提的是,使用表达式树而不是 LCG 的一个缺点是表达式树的构建和编译肯定比直接发出原始操作码要慢。假设您正在缓存已编译的方法,这不太可能是一个重大问题,但这是仍然可能迫使您使用 LCG 的一个原因。

于 2011-04-12T19:11:02.697 回答
0

LCG 是指超出范围后可以收集的方法。LINQ 表达式使用 LCG 或法线反射发射......所以 LCG 绝对没有死。此外,LINQ 表达式不支持 ref 参数、ldtoken、实例方法、属性等所有内容

于 2014-09-30T05:52:43.680 回答