代码之家  ›  专栏  ›  技术社区  ›  TheSoftwareJedi jac

当使用嵌套的lambdaexpressions编译lambdaexpression时,它们还会编译吗?

  •  4
  • TheSoftwareJedi jac  · 技术社区  · 6 年前

    在运行时构建lambda expression时,如果使用lambda expression作为调用表达式的参数(如使用linq时),则编译主lambda,嵌套lambda是否也编译或需要编译?

    如果我使用lambdaExpression作为方法的参数,则代码的功能相同 Func<T, T2> 或者如果我编译它并使用 Expression.Constant 在编译的 Func .

    未编译:

        var selectParam = Expression.Parameter(propType, "selectParam");
        var selectExp = Expression.Call(typeof(System.Linq.Enumerable).GetMethods().First(a => a.Name == "Select" && /*Func<TSource,TResult>*/ a.GetParameters().Last().ParameterType.GenericTypeArguments.Length == 2).MakeGenericMethod(propType, typeof(int)),
                                        whereExp,
                                        Expression.Lambda(Expression.Property(selectParam, "Length"), selectParam));
    

    编译:

        var selectParam = Expression.Parameter(propType, "selectParam");
        var selectExp = Expression.Call(typeof(System.Linq.Enumerable).GetMethods().First(a => a.Name == "Select" && /*Func<TSource,TResult>*/ a.GetParameters().Last().ParameterType.GenericTypeArguments.Length == 2).MakeGenericMethod(propType, typeof(int)),
                                        whereExp,
                                        Expression.Constant(Expression.Lambda(Expression.Property(selectParam, "Length"), selectParam).Compile())); //compile
    

    我正在构建的表达式在一个循环中被调用数百万次,所以我想知道编译外部lambda是否能够正确地编译内部lambda。

    既然这不容易解释,看我的小提琴 here .

    我很肯定他们 不会 编译为被调用的方法可能希望它们作为表达式来解析它们。在这种情况下,当这样使用时,编译它们是否会提高运行时性能?

    在更高的层次上思考,当以一种标准的方式在循环中使用时——这是优化的吗?当然,在对数组或类似数组执行LINQ时,不会对每个调用进行编译?

    1 回复  |  直到 6 年前
        1
  •  4
  •   Aleks Andreev Md. Suman Kabir    6 年前


    private static Expression<Func<int>> ActuallyInnerAlsoCompile()
    {
        var strType = typeof(string);
        var intType = typeof(int);
        var enumearbleType = typeof(Enumerable);
    
        var array = Expression.NewArrayInit(strType, Expression.Constant("test"), Expression.Constant("test2"));
    
        var x = Expression.Parameter(strType, "whereParam");
        var whereExp = Expression.Call(enumearbleType,
            "Where",
            new[] {strType},
            array,
            Expression.Lambda(Expression.NotEqual(Expression.PropertyOrField(x, "Length"), Expression.Constant(4)), x));
    
        var selectExp = Expression.Call(enumearbleType,
            "Select",
            new[] {strType, intType},
            whereExp,
            Expression.Lambda(Expression.PropertyOrField(x, "Length"), x));
    
        var firstOrDefault = Expression.Call(enumearbleType,
            "FirstOrDefault",
            new[] {intType},
            selectExp);
    
        return Expression.Lambda<Func<int>>(firstOrDefault);
    }
    

    answer

    var lambda = ActuallyInnerAlsoCompile();
    
    var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
        new AssemblyName("dynamicAssembly"),
        AssemblyBuilderAccess.Save);
    
    var dm = dynamicAssembly.DefineDynamicModule("dynamicModule", "dynamic.dll");
    var dt = dm.DefineType("dynamicType");
    var m1 = dt.DefineMethod(
        "dynamicMethod",
        MethodAttributes.Public | MethodAttributes.Static);
    
    lambda.CompileToMethod(m1);
    dt.CreateType();
    
    dynamicAssembly.Save("dynamic.dll");
    

    // Decompiled with JetBrains decompiler
    // Type: dynamicType
    // Assembly: dynamicAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    // MVID: 94346EDD-3BCD-4EB8-BA4E-C25343918535
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    internal class dynamicType
    {
      public static int dynamicMethod()
      {
        return ((IEnumerable<string>) new string[2]
        {
          "test",
          "test2"
        }).Where<string>(new Func<string, bool>(dynamicType.\u003CExpressionCompilerImplementationDetails\u003E\u007B1\u007Dlambda_method)).Select<string, int>(new Func<string, int>(dynamicType.\u003CExpressionCompilerImplementationDetails\u003E\u007B2\u007Dlambda_method)).FirstOrDefault<int>();
      }
    
      private static bool \u003CExpressionCompilerImplementationDetails\u003E\u007B1\u007Dlambda_method(string whereParam)
      {
        return whereParam.Length != 4;
      }
    
      private static int \u003CExpressionCompilerImplementationDetails\u003E\u007B2\u007Dlambda_method(string whereParam)
      {
        return whereParam.Length;
      }
    }