轻量级代码生成(LCG)是否已经死亡?

时间:2010-06-08 23:03:48

标签: .net-4.0 code-generation lcg

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

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

为什么有人会在任何新代码中使用LCG?那表达树不能做什么吗?或者它现在是一个“死”的功能?

4 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:0)

嗯,这个问题现在很老了,我正在等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的一个原因。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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