一、什么是表達式樹
既然是樹感覺是一種數據結構,改結構是一個樹形,而且每個節點是一個表達式。例如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; }