在其他BlockExpressions中执行额外的BlockExpressions会影响代码生成

本文关键字:BlockExpressions 影响 代码生成 其他 执行 | 更新日期: 2023-09-27 18:30:07

在C#表达式树中,

.Block(
    ConsoleApplication2.A $var1,
    ConsoleApplication2.B $var2) {
     .Block() {
        .Block() {
           $var1 = .New ConsoleApplication2.A();
           $var1
        };
        .Block() {
           $var2 = .New ConsoleApplication2.B($var1);
           $var2
        }
   }
}

与相比,上述表达式是否生成较差的代码质量

.Block(
    ConsoleApplication2.A $var1,
    ConsoleApplication2.B $var2) {
     $var1 = .New ConsoleApplication2.A();
     $var2 = .New ConsoleApplication2.B($var1);
}

它们在功能上是等效的,但第一个是我经常通过基于访问者模式的修改得到的。

有没有办法将所有占位符(即没有变量??)的块"减少"或"折叠"到父块中?也许会利用另一位访客?我想不通。

在其他BlockExpressions中执行额外的BlockExpressions会影响代码生成

在IL级别,没有块的概念,所以我希望这两个表达式产生相同(或非常相似)的IL代码。

要验证这一点,可以使用Reflection.Emit和CompileToMethod()创建一个程序集,该程序集在单独的方法中同时具有这两个选项。然后,您可以使用ildasm查看两种方法的IL,以验证代码是否确实相同:

.locals init (
    [0] class [ConsoleApplication1]ConsoleApplication1.A a,
    [1] class [ConsoleApplication1]ConsoleApplication1.B b)
L_0000: newobj instance void [ConsoleApplication1]ConsoleApplication1.A::.ctor()
L_0005: stloc.0 
L_0006: ldloc.0 
L_0007: newobj instance void [ConsoleApplication1]ConsoleApplication1.B::.ctor(class [ConsoleApplication1]ConsoleApplication1.A)
L_000c: stloc.1 
L_000d: ret 

创建程序集的代码可能如下所示:

var var1 = Expression.Variable(typeof(A), "var1");
var var2 = Expression.Variable(typeof(B), "var2");
Expression<Action> withBlocks =
    Expression.Lambda<Action>(
        Expression.Block(
            new[] { var1, var2 },
            Expression.Block(
                Expression.Block(
                    Expression.Assign(
                        var1,
                        Expression.New(typeof(A).GetConstructors().Single())),
                    var1),
                Expression.Block(
                    Expression.Assign(
                        var2,
                        Expression.New(
                            typeof(B).GetConstructors().Single(), var1)),
                    var2))));
Expression<Action> withoutBlocks =
    Expression.Lambda<Action>(
        Expression.Block(
            new[] { var1, var2 },
            Expression.Assign(
                var1, Expression.New(typeof(A).GetConstructors().Single())),
            Expression.Assign(
                var2,
                Expression.New(typeof(B).GetConstructors().Single(), var1))));
var assembly = AssemblyBuilder.DefineDynamicAssembly(
    new AssemblyName("test"), AssemblyBuilderAccess.Save);
var module = assembly.DefineDynamicModule("test.dll");
var type = module.DefineType("Type");
var withBlocksMethod = type.DefineMethod(
    "WithBlocks", MethodAttributes.Public | MethodAttributes.Static,
    typeof(void), Type.EmptyTypes);
withBlocks.CompileToMethod(withBlocksMethod);
var withoutBlocksMethod = type.DefineMethod(
    "WithoutBlocks", MethodAttributes.Public | MethodAttributes.Static,
    typeof(void), Type.EmptyTypes);
withoutBlocks.CompileToMethod(withoutBlocksMethod);
type.CreateType();
assembly.Save("test.dll");
相关文章:
  • 没有找到相关文章