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

Gre*_*ech 6 code-generation .net-4.0 lcg

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

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

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

Gre*_*ech 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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