代码之家  ›  专栏  ›  技术社区  ›  Greg Beech

轻量级代码生成(LCG)死了吗?

  •  6
  • Greg Beech  · 技术社区  · 15 年前

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

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

    那么,有没有理由在任何新代码中使用LCG呢?有什么是表达式树无法做到的吗?或者它现在是一个“死”功能?

    4 回复  |  直到 15 年前
        1
  •  3
  •   Community CDub    13 年前

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

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

        2
  •  1
  •   Greg Beech    14 年前

    这个问题现在已经很老了,我在等答案 tf get 完成。。。所以我自己来回答。

    是的,LCG在大多数情况下已经死亡。

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

    但是,也许最重要的是,表达式树在某种程度上是可组合的,可以避免反射。事实并非如此。这意味着用于运行时代码生成的组件的体系结构可以更加模块化,甚至允许插件扩展代码生成框架。

    我发现有一件事得到了反思的支持。正在设置表达式树中不直接支持的发射 .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的一个原因。

        3
  •  1
  •   Alex Petrov    10 年前

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

        4
  •  0
  •   Ziad Elmalki    10 年前

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