表达式树

 一、什么是表达式树 

       既然是树感觉是一种数据结构,改结构是一个树形,而且每个节点是一个表达式。例如1+2 就是一个表达式,我觉得可以理解为一个复杂的函数结构。一个例子 var sum = 1 + 2;

其实该语句可以分解成以下:

具有赋值 (var sum = 1 + 2;) 的变量声明语句

    • 隐式变量类型声明 (var sum)
      • 隐式 var 关键字 (var)
      • 变量名称声明 (sum)
    • 赋值运算符 (=)
    • 二进制加法表达式 (1 + 2)
      • 左操作数 (1)
      • 加法运算符 (+)
      • 右操作数 (2)

  图画的不是很好,但是可以很直观看出是一个树形结构:

 

 

 

二、怎么创建声明表达式树

        

var one = Expression.Constant(1, typeof(int));
var two = Expression.Constant(2, typeof(int));
var addition = Expression.Add(one, two);

这样其实就创建了一个 1+2 这样的表达式。

 但是你不能这样创建

Expression<Func<int, int, int>> expr = (x, y) => { return x+y; }; 

不能直接给他赋值一个lambda的,可以写成这样:Expression<Func<int,int,int>> sum = (x,y) => x+ y;;其实表达式树主要有几部分组成:

Body:指表达式的主体部分;

Parameters:指表达式的参数;

NodeType:指表达式的节点类型,如在上面的例子中,它的节点类型是Lambda;

Type:指表达式的静态类型,在上面的例子中,Type为Fun<int,int,int>。

表达式树可以转换成lambda,如:

var lambda = Expression.Lambda(addition);

表达式树加入其他方法:

var sqrtMethod = typeof(Math).GetMethod("Sqrt", new[] { typeof(double) });

var distance = Expression.Call(sqrtMethod, sum);

首先,在使用它们之前,需要创建表示参数或局部变量的对象。 创建这些对象后,可以在表达式树中任何需要的位置使用它们。

其次,需要使用反射 API 的一个子集来创建 MethodInfo 对象,以便创建表达式树以访问该方法。 必须仅限于 .NET Core 平台上提供的反射 API 的子集。 同样,这些技术将扩展到其他表达式树。

当然啦,表达式树可以创建的很复杂。不过一般我们都不需要这样子去做,因为很难阅读,其实就是一个复杂的方法,我们可以换种思路去实现就好了。

三、表达式树的执行

 

Expression<Func<int>> add = () => 1 + 2;//定义表达式树

var func = add.Compile(); // 创建委托

var answer = func(); // 执行委托

 

四、表达式树有什么作用

(一)动态排序

其实我们在开发项目系统的时候经常会遇到排序字段可变的 。如果全部使用硬编码固然可以,但是不够灵活也不够优雅。所以,今天我们也参考一下国外的一篇文章,看一下人家是怎么构建动态排序的。

我们首先要分析一下,在linq中orderby 这个方法到底是什么:public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);

这是一个扩展方法,然后参数就是一个我们今天的主题表达式树,这个表达式树对应的lambda 就是一个Tsource类型的参数,返回一个Tkey类型的,这样的一个主体。

我们需要重写OrderBy这个方法,这个方法的功能是根据TSource和需要排序的字段动态的返回IQueryable<TSource>。看下下面的代码:

 

     public static IQueryable<T> GenericEvaluateOrderBy<T>(this IQueryable<T> query, string sort, string order = "DESC")
        {
            if (string.IsNullOrEmpty(sort))
                throw new Exception("必须指定排序字段!");

            PropertyInfo sortProperty = typeof(T).GetProperty(sort, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            if (sortProperty == null)
            {
                throw new Exception("找不到指定的排序字段");
                //sortProperty = typeof(T).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            }
            ParameterExpression param = Expression.Parameter(typeof(T), "t");
            Expression body = param;
            if (Nullable.GetUnderlyingType(body.Type) != null)
                body = Expression.Property(body, "Value");
            body = Expression.MakeMemberAccess(body, sortProperty);
            LambdaExpression keySelectorLambda = Expression.Lambda(body, param);

            if (string.IsNullOrEmpty(order))
                order = "DESC";
            string queryMethod = order.ToUpper() == "DESC" ? "OrderByDescending" : "OrderBy";
            query = query.Provider.CreateQuery<T>(Expression.Call(typeof(Queryable), queryMethod,
                                                               new Type[] { typeof(T), body.Type },
                                                               query.Expression,
                                                               Expression.Quote(keySelectorLambda)));
            return query;
        }

 

posted @ 2018-11-15 23:16  UpOcean  阅读(5029)  评论(0编辑  收藏  举报