Expression表达式树(C#)

Lambda表达式:

1.下面举例通过Lambda表达式创建了一个用于验证Name的Func委托。

     //通过Lambda表达式创建一个对象的Name属性验证委托
     Func<SearchInfo, bool> func = x => x.Name.Equals("5");
复制代码
    /// <summary>
    /// 测试类
    /// </summary>
    public class SearchInfo
    {
        public string Name { get; set; }

        public string Code { get; set; }
    }
复制代码

  2.测试调用, 下面验证 "6" 是否和 "5" 相等, 结果false

           //res=false
            bool res = func(new SearchInfo() { Name = "6" });

那么问题来了, 如果我希望验证的结果不是 "5" 而是其他的内容: "7","9" ...等等呢? ,

那么接下来封装一个Func, 允许自定义验证结果:

        public static Func<SearchInfo, bool> Func(string arr)
        {
            return x => x.Name.Equals(arr); //这一步将Equals中校验的内容进行了参数封装
        }

测试代码: 

            bool f1=  Func("6")(new SearchInfo() { Name = "6" }); //true
            bool f2 = Func("7")(new SearchInfo() { Name = "6" }); //false
            bool f3 = Func("8")(new SearchInfo() { Name = "6" }); //false

如上所示, 我们成功的把Equals中的验证结果封装了起来。但是 !实际应用这还不够,

如果你要校验的不是Name 或是Code,  Equals 变成其他 Contains呢?如下:

﹋﹊﹋﹊﹋﹊﹋﹊﹋分割线﹊﹋﹊﹋﹊﹋﹊﹋﹊ 

Expression(表达式树)

位于 System.Linq.Expressions 命名空间下, 下面介绍如何以上简单的示例创建一个动态的Expression, 类型参数为委托类型:

复制代码
//
    // 摘要:
    //     将强类型化的 Lambda 表达式表示为表达式树形式的数据结构。 此类不能被继承。
    //
    // 类型参数:
    //   TDelegate:
    //     该委托的类型, System.Linq.Expressions.Expression`1 表示。
    public sealed class Expression<TDelegate> : LambdaExpression
    {
        //
        // 摘要:
        //     编译表达式树由描述为可执行代码的 lambda 表达式,并生成一个委托,表示 lambda 表达式。
        //
        // 返回结果:
        //     类型的委托 TDelegate 表示所描述的已编译的 lambda 表达式 System.Linq.Expressions.Expression`1。
        public TDelegate Compile();
        //
        // 摘要:
        //     将生成一个委托,表示 lambda 表达式。
        //
        // 参数:
        //   debugInfoGenerator:
        //     由编译器用于将标记序列点并添加批注的本地变量的调试信息生成器。
        //
        // 返回结果:
        //     一个包含已编译的版本的 lambda 的委托。
        public TDelegate Compile(DebugInfoGenerator debugInfoGenerator);
        //
        // 摘要:
        //     创建一个新的表达式,它类似于此表达式,但使用所提供的子级。 如果所有子级均相同,它将返回此表达式。
        //
        // 参数:
        //   body:
        //     System.Linq.Expressions.LambdaExpression.Body 结果属性。
        //
        //   parameters:
        //     System.Linq.Expressions.LambdaExpression.Parameters 结果属性。
        //
        // 返回结果:
        //     如果子级未更改,则为此表达式;否则为具有已更新子级的表达式。
        public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters);
        protected internal override Expression Accept(ExpressionVisitor visitor);
    }
复制代码

示例(用表达式的形式):

Expression<Func<SearchInfo, bool>> lambda = x => x.Name.Equals("5");
 
bool res = lambda.Compile()(new SearchInfo() { Name = "6" }); // 结果 : false

注释: 为了能够了解 Expression<Func<SearchInfo, bool>> lambda = x => x.Name.Equals("5") 这段代码的结构,

接下来用 ILSpy 反编译, 查看到该代码生成了如下: 

复制代码
            ParameterExpression parameterExpression = Expression.Parameter(typeof(SearchInfo), "x"); 
            Expression<Func<SearchInfo, bool>> expression = Expression.Lambda<Func<SearchInfo, bool>>(Expression.Call(
Expression.Property(parameterExpression, (MethodInfo)MethodBase.GetMethodFromHandle(ldtoken(get_Name()))),
(MethodInfo)MethodBase.GetMethodFromHandle(ldtoken(Equals())),
new Expression[] { Expression.Constant("5", typeof(string)) }), new ParameterExpression[] { parameterExpression });
复制代码

我们分解以上代码(先用数字标识):

1. ParameterExpression parameterExpression = Expression.Parameter(typeof(SearchInfo), "x");   参数表达式

2. Expression.Property(parameterExpression, (MethodInfo)MethodBase.GetMethodFromHandle(ldtoken(get_Name())))   属性表达式

3. new Expression[] { Expression.Constant("5", typeof(string)) } 常数表达式

4. (MethodInfo)MethodBase.GetMethodFromHandle(ldtoken(Equals()))  方法调用表达式

5. Expression.Lambda<Func<SearchInfo, bool>>(Expression.Call( 2, 4, 3), 1);   创建Lambda表达式

接下来回到最开始的Lambda表达式, 图解说明以上的代码分别代表Lambda表达式的每个部分:

理解上表达式生成的5个步骤, 接下来还原一个表达式完整的创建过程, 如下: 

复制代码
            //1.创建参数表达式
            ParameterExpression parameterExpression = Expression.Parameter(typeof(SearchInfo), "x");

            //2.创建属性表达式
            Expression proerty = Expression.Property(parameterExpression, typeof(SearchInfo).GetProperty("Name"));

            //3.创建常数表达式
            ConstantExpression constantExpression = Expression.Constant("5", typeof(string));

            //4.创建方法调用表达式
            MethodCallExpression toString = Expression.Call(
                proerty,
                typeof(SearchInfo).GetMethod("Equals"),
                 new Expression[] { constantExpression });

            //5.创建Lambda表达式
            Expression<Func<SearchInfo, bool>> lambda = Expression.Lambda<Func<SearchInfo, bool>>(toString, new ParameterExpression[]
            {
                    parameterExpression
            });
复制代码

以上则是如何创建一个表达式树, 测试调用, 如下: 

 bool res = lambda.Compile()(new SearchInfo() { Name = "55" }); // “5”!=“55”   结果: false

注: Compile() 为lambda的编译, 后面则才能进行参数的传递

基于类(Class)动态生成表达式:

复制代码
/// <summary>
    /// 测试类
    /// </summary>
    public class SearchInfo
    {
        public string Name { get; set; }

        public string Code { get; set; }

        public string Id { get; set; }

        public string Addr { get; set; }

        public string Res { get; set; }
    }
复制代码

 

复制代码
public static Func<T, bool> GenerateExpression<T>(T searchModel) where T : class, new()
        {
            List<MethodCallExpression> mcList = new List<MethodCallExpression>();
            Type type = searchModel.GetType();
            ParameterExpression parameterExpression = Expression.Parameter(type, "x");
            var pros = type.GetProperties();
            foreach (var t in pros)
            {
                var objValue = t.GetValue(searchModel, null);
                if (objValue != null)
                {
                    Expression proerty = Expression.Property(parameterExpression, t);
                    ConstantExpression constantExpression = Expression.Constant(objValue, t.PropertyType);
                    mcList.Add(Expression.Call(proerty, typeof(string).GetMethod("Contains"), new Expression[] { constantExpression }));
                }
            }

            if (mcList.Count == 0)
                return Expression.Lambda<Func<T, bool>>(Expression.Constant(true, typeof(bool)), new ParameterExpression[] { parameterExpression }).Compile();
            else
                return Expression.Lambda<Func<T, bool>>(MethodCall(mcList), new ParameterExpression[] { parameterExpression }).Compile();
        }

        public static Expression MethodCall<T>(List<T> mcList) where T : MethodCallExpression
        {
            if (mcList.Count == 1) return mcList[0];
            BinaryExpression binaryExpression = null;
            for (int i = 0; i < mcList.Count; i += 2)
            {
                if (i < mcList.Count - 1)
                {
                    BinaryExpression binary = Expression.OrElse(mcList[i], mcList[i + 1]);
                    if (binaryExpression != null)
                        binaryExpression = Expression.OrElse(binaryExpression, binary);
                    else
                        binaryExpression = binary;
                }
            }
            if (mcList.Count % 2 != 0)
                return Expression.OrElse(binaryExpression, mcList[mcList.Count - 1]);
            else
                return binaryExpression;
        }
复制代码

测试代码 : 

复制代码
        static void Main(string[] args)
        {
            var func = GenerateExpression(new SearchInfo());

            List<SearchInfo> List = new List<SearchInfo>();
            List.Add(new SearchInfo() { Code = "1", Id = "1", Name = "3", Addr = "5", Res = "6" });
            List.Add(new SearchInfo() { Code = "2", Id = "2", Name = "4", Addr = "5", Res = "6" });
            List.Add(new SearchInfo() { Code = "3", Id = "3", Name = "5", Addr = "5", Res = "6" });
            List.Add(new SearchInfo() { Code = "4", Id = "4", Name = "6", Addr = "5", Res = "6" });
            List.Add(new SearchInfo() { Code = "5", Id = "5", Name = "7", Addr = "5", Res = "6" });
            List.Add(new SearchInfo() { Code = "6", Id = "6", Name = "8", Addr = "5", Res = "6" });
            List.Add(new SearchInfo() { Code = "7", Id = "7", Name = "9", Addr = "5", Res = "6" });
            List.Add(new SearchInfo() { Code = "8", Id = "8", Name = "3", Addr = "5", Res = "6" });

            var ii = List.Where(func).ToList(); //8个结果
        }
复制代码

***********转摘:https://www.cnblogs.com/zh7791/p/9928133.html

 
原文地址:https://www.cnblogs.com/linybo/p/13218769.html