Search code examples
linqreflectionlambdareflector

Reflector generated Lambda Expression, how to get back back actual Linq Query?


I'm using Reflector to decompile some binaries. I'm having problem with Lambda Expressions and methodof which doesn't compile. lambda Expression seems super complicated to me and I have no idea how to convert it back to Compilable LINQ Code. here is the code:

public double? LoadSumRialAmount(long functionId, long? subFunctionId)
{
        ParameterExpression expression;
        if (!subFunctionId.HasValue)
        {
            return (from func in base.MetaData.SubFunction
                where func.FunctionId == functionId
                select func).Select<SubFunctionEntity, double?>(System.Linq.Expressions.Expression.Lambda<Func<SubFunctionEntity, double?>>(System.Linq.Expressions.Expression.Multiply(System.Linq.Expressions.Expression.Property(expression = System.Linq.Expressions.Expression.Parameter(typeof(SubFunctionEntity), "func"), (MethodInfo) methodof(SubFunctionEntity.get_Volume)), System.Linq.Expressions.Expression.Property(expression, (MethodInfo) methodof(SubFunctionEntity.get_RialAmount))), new ParameterExpression[] { expression })).Sum();
        }
        return (from func in base.MetaData.SubFunction
            where (func.FunctionId == functionId) && (func.SubFunctionId != subFunctionId)
            select func).Select<SubFunctionEntity, double?>(System.Linq.Expressions.Expression.Lambda<Func<SubFunctionEntity, double?>>(System.Linq.Expressions.Expression.Multiply(System.Linq.Expressions.Expression.Property(expression = System.Linq.Expressions.Expression.Parameter(typeof(SubFunctionEntity), "func"), (MethodInfo) methodof(SubFunctionEntity.get_Volume)), System.Linq.Expressions.Expression.Property(expression, (MethodInfo) methodof(SubFunctionEntity.get_RialAmount))), new ParameterExpression[] { expression })).Sum();
}

p.s another error is SubFunctionEntity class has a "Volume" property, and I don't understand why this code is calling some kind of static property on it like: SubFunctionEntity.get_Volume


Solution

  • Have you tried ILSpy? It even has some options to control if you want to produce LINQ "function" syntax or from... where syntax (View->Options->Decompiler->Decompile query expression and Decompile anonymous methods/lambdas)

    For your other question: SubFunctionEntity.get_Volume is the getter of the property Volume of the class SubFunctionEntity.

    (MethodInfo) methodof(SubFunctionEntity.get_Volume) is the same as typeof(SubFunctionEntity).GetProperty("Volume").GetGetMethod(), only done at compile time instead that at runtime. The problem is that C# doesn't have a methodof "function".

    If you really want to use what the Reflector gave you, this is the "corrected" version:

    public double? LoadSumRialAmount(long functionId, long? subFunctionId)
    {
        ParameterExpression expression;
        if (!subFunctionId.HasValue)
        {
            return (from func in base.MetaData.SubFunction
                    where func.FunctionId == functionId
                    select func).Select<SubFunctionEntity, double?>(Expression.Lambda<Func<SubFunctionEntity, double?>>(Expression.Multiply(Expression.Property(expression = Expression.Parameter(typeof(SubFunctionEntity), "func"), typeof(SubFunctionEntity).GetProperty("Volume").GetGetMethod()), Expression.Property(expression, typeof(SubFunctionEntity).GetProperty("RialAmount").GetGetMethod())), new ParameterExpression[] { expression })).Sum();
        }
        return (from func in base.MetaData.SubFunction
                where (func.FunctionId == functionId) && (func.SubFunctionId != subFunctionId)
                select func).Select<SubFunctionEntity, double?>(Expression.Lambda<Func<SubFunctionEntity, double?>>(Expression.Multiply(Expression.Property(expression = Expression.Parameter(typeof(SubFunctionEntity), "func"), typeof(SubFunctionEntity).GetProperty("Volume").GetGetMethod()), Expression.Property(expression, typeof(SubFunctionEntity).GetProperty("RialAmount").GetGetMethod())), new ParameterExpression[] { expression })).Sum();
    }
    

    Note that you'll need some using:

    using System.Linq;
    using System.Linq.Expressions;
    

    Ah... the most complex expression is : func => (func.Volume * func.RialAmount) so you could write the method as:

    public double? LoadSumRialAmount(long functionId, long? subFunctionId)
    {
        if (!subFunctionId.HasValue)
        {
            return (from func in base.MetaData.SubFunction
                    where func.FunctionId == functionId
                    select func).Select(func => (func.Volume * func.RialAmount)).Sum();
        }
        return (from func in base.MetaData.SubFunction
                where (func.FunctionId == functionId) && (func.SubFunctionId != subFunctionId)
                select func).Select(func => (func.Volume * func.RialAmount)).Sum();
    }
    

    Addendum: checked, the ILSpy produce random garbage similar-but different to Reflector