一、什么是表达式树
既然是树感觉是一种数据结构,改结构是一个树形,而且每个节点是一个表达式。例如1+2 就是一个表达式,我觉得可以理解为一个复杂的函数结构。一个例子 var sum = 1 + 2;
其实该语句可以分解成以下:
具有赋值 (var sum = 1 + 2;
) 的变量声明语句
-
- 隐式变量类型声明 (
var sum
)- 隐式 var 关键字 (
var
) - 变量名称声明 (
sum
)
- 隐式 var 关键字 (
- 赋值运算符 (
=
) - 二进制加法表达式 (
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; }