动态表达式:编译器如何编译以及期望的lamda表达式

时间:2018-04-19 07:46:56

标签: c# lambda dynamic-queries

我正在关注此问题Returning a nested generic Expression<Func<T, bool>> 我对编译器如何读取并将其编译为

感兴趣

例如

ParameterExpression pe = Expression.Parameter(typeof(T), "p");
PropertyInfo pi = typeof(T).GetProperty(prop);
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
ConstantExpression ce = Expression.Constant(val);
BinaryExpression be = Expression.Equal(me, ce);
return Expression.Lambda<Func<T, bool>>(be, pe);

更新还需要解释每种方法

我的问题是编译后我应该期待什么lamda表达式?

1 个答案:

答案 0 :(得分:1)

请参阅以下代码中的评论。

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

namespace ConsoleApp5
{
    class Program
    {
        static void Main(string[] args)
        {
            var myType = new MyType();
            myType.p = "Some Value";

            var compareMethod = DoWork<MyType>("Some Value", "p");
            var isEqual = compareMethod(myType);
        }

        public static Func<T, bool>  DoWork<T>(object val, string prop)
        {
            //The code below will construct an expression like 'p => p.prop == value'
            //Creates the parameter part of an expression. So the 'p =>' part of the expression.
            ParameterExpression pe = Expression.Parameter(typeof(T), "p");
            //Get access to the property info, like the getter and setter.
            PropertyInfo pi = typeof(T).GetProperty(prop);
            // // Constructs the part of the expression where the member is referenced, so the 'p.prop' part.
            MemberExpression me = Expression.MakeMemberAccess(pe, pi);
            //Creates the constant part of the expression, the 'value' part.
            ConstantExpression ce = Expression.Constant(val);
            //creates the comparison part '==' of the expression.
            //So this requires the left and right side of 'left == right'
            //Which is the property and the constant value.
            //So 'p.prop == value'
            BinaryExpression be = Expression.Equal(me, ce);
            //Puts the 'p => ' and 'p.prop == value' parts of the expression together to form the 
            //complete lambda
            //Compile it to have an executable method according to the same signature, as 
            //specified with Func<T, bool>, so you put a class in of type T and 
            //the 'p.prop == value' is evaluated, and the result is returned.
            return Expression.Lambda<Func<T, bool>>(be, pe).Compile();
        }
    }

    public class MyType
    {
        public string p { get; set; }
    }
}

那就是说,我认为这只是比较的复杂方式。您考虑的用例可能是合理的。您是否正在使用LINQ-to-SQL,以至于您必须使用表达式?在大多数情况下,从我的epxerience,您可以使用Funcs和接口解决这个问题,也可以在第三方类的情况下与包装类结合使用。代码本身可能在内存中创建一些MSIL,然后使用CLR的Just-In-Time编译器在内存中将其编译为本机代码,其中内存的分配被标记为可执行。我没有详细了解它是如何工作的,这只是一个猜测。有关如何为不同目的标记内存分配的详细信息,请参阅Memory Protection Constants