在上一篇中,咱們認識了什麼是表達式樹、什麼是委託,以及它們的關係。多是我功力很差,貌似你們都不怎麼關注,沒有講解出不一樣角度的問題。html
學習一種新技術,是枯燥的過程,只有在你掌握後並能運用時才能從它身上獲得樂趣。git
作程序開發是一羣很奇怪的人羣,咱們竟然能夠經過密密麻麻的英文字符加上標點符號從中找到樂趣,確實很奇怪。github
考慮到你們接觸新技術須要一個過程:express
其實對於不少人來講已經不是新技術了,不過您會耐心看本篇後續的文章,說明您可能對這一項技術運用的並非很熟練設計模式
因此我不打算一上來,就放一大堆代碼,而後解釋這是什麼,那是什麼,由於會接觸不少新的關鍵詞,這樣你們學習起來會也會很痛苦數據結構
本系列後面的全部篇幅都只在每篇中提一個新概念,這樣你們學習起來能夠減小學習的範圍。框架
而後也讓你們完全搞懂每種類型的做用,同時我會用Lambda方式、動態構造、以及表達式樹的結構三種方式來共同研究每篇課題的新類型。ide
LambdaExpression是繼承自Expression的。LambdaExpression的具體表現是:Expression<Func<>>或者Expression<Action<>> 學習
這段不明白不要緊,看下面示例就知道了this
首先,咱們先從MSDN上看它的註釋說明:
描述一個 lambda 表達式。 這將捕獲與 .NET 方法體相似的代碼塊。
看MSDN註釋,咱們仍是沒搞懂它是什麼意思,通俗的講:一段包含有運算表達式的代碼,就是LambdaExpression。
好吧,我說了吧,個人功底不行,您越看越不明白了………………(比MSDN解釋的還更糟糕)
Expression<Func<int,int>> exp1 = o=> o + 1; Expression<Action<int>> exp2 = o=> o = 1 + 2;
這種經過 o=> ...... 定義的就是LambdaExpression了。回過頭,我上面說的:
一段包含有運算表達式的代碼,就是LambdaExpression。
這樣子是否是更容易理解了?固然上面只作了 加法操做,固然不只僅是這些操做,好比:
Expression<Func<UserVO, object>> exp = o => o.ID != 1 && (o.UserName == "steden" || o.UserName == "farseer.net")
再好比在咱們的Linq To Object中(固然這裏是純委託類型:Func<int,bool>,但它也是lambda表達式(注意不是表達式樹))
var lst = new List<int>(); lst.Where(o => o > 0);
這些都是Lambda的定義。而且咱們在上篇中也學習到如何將Expression<Func<UserVO,object>>轉換成Func<UserVO,object>。
這時候聰明的讀者會想,即然我能夠直接定義o=>.... ,爲何還要去理解LambdaExpression,反正C#編譯器會把它轉成LambdaExpression,根本不用咱們關心。
確實是這樣,若是咱們不須要動態構造它
個人意思是在程序運行時動態的生成它,則不是在編寫代碼的時候定義它
的時候,確實不用管是否是LambdaExpression了,只管在代碼上定義就好了。
可是,其實不少場景下,咱們是須要動態的構造它的,而後將它傳遞給其它地方,讓他們去解析它,好比說:
場景:在系統分層中,咱們有個實體類,好比叫:UserVO(它屬於xxx.Entity類庫)。而在咱們的底層中,須要動態對實體類生成一些「通用的」操做(好比邏輯刪除功能)。可是咱們知道底層是不知道上層有什麼數據類型,甚至被誰調用了也不知道。所以這個時候,我就必須以動態構造的方式來建立它了。(由於我根本不知道有UserVO這個類)
事實上,上面舉的場景例子不只僅是LambdaExpression,其它的Expression也是如此。
在講動態構造前,我以爲仍是先讓你們學習如何解析它,必境咱們的學習是先了解它的內部結構,才更好的知道如何構造它,不是嗎?
這要請出咱們偉大的ExpressionVisitor類了。事實上,在個人Farseer.Net ORM框架中從新封裝了這個類,叫AbsExpressionVisitor.cs,它是我全部表達式樹訪問器的基類,另外派出了一個專門提供給SQL的解析器,叫AbsSqlVisitor.cs
其中有個入口方法:
protected virtual Expression Visit(Expression exp)
ExpressionVisitor以訪問者模式(設計模式)來訪問這個表達式樹。能夠看到有個:exp.NodeType屬性,返回的是:ExpressionType枚舉:
protected virtual Expression Visit(Expression exp) { if (exp == null) return exp; switch (exp.NodeType) { case ExpressionType.Negate: case ExpressionType.NegateChecked: case ExpressionType.Not: case ExpressionType.Convert: case ExpressionType.ConvertChecked: case ExpressionType.ArrayLength: case ExpressionType.Quote: case ExpressionType.TypeAs: return this.VisitUnary((UnaryExpression)exp); case ExpressionType.Add: case ExpressionType.AddChecked: case ExpressionType.Subtract: case ExpressionType.SubtractChecked: case ExpressionType.Multiply: case ExpressionType.MultiplyChecked: case ExpressionType.Divide: case ExpressionType.Modulo: case ExpressionType.And: case ExpressionType.AndAlso: case ExpressionType.Or: case ExpressionType.OrElse: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.Coalesce: case ExpressionType.ArrayIndex: case ExpressionType.RightShift: case ExpressionType.LeftShift: case ExpressionType.ExclusiveOr: return this.VisitBinary((BinaryExpression)exp); case ExpressionType.TypeIs: return this.VisitTypeIs((TypeBinaryExpression)exp); case ExpressionType.Conditional: return this.VisitConditional((ConditionalExpression)exp); case ExpressionType.Constant: return this.VisitConstant((ConstantExpression)exp); case ExpressionType.Parameter: return this.VisitParameter((ParameterExpression)exp); case ExpressionType.MemberAccess: return this.VisitMemberAccess((MemberExpression)exp); case ExpressionType.Call: return this.VisitMethodCall((MethodCallExpression)exp); case ExpressionType.Lambda: return this.VisitLambda((LambdaExpression)exp); case ExpressionType.New: return this.VisitNew((NewExpression)exp); case ExpressionType.NewArrayInit: case ExpressionType.NewArrayBounds: return this.VisitNewArray((NewArrayExpression)exp); case ExpressionType.Invoke: return this.VisitInvocation((InvocationExpression)exp); case ExpressionType.MemberInit: return this.VisitMemberInit((MemberInitExpression)exp); case ExpressionType.ListInit: return this.VisitListInit((ListInitExpression)exp); default: throw new Exception(string.Format("Unhandled expression type: '{0}'", exp.NodeType)); }
而後根據傳入進來的表達式樹,進行一一解析,您能從中看到,當case 到 ExpressionType.Lambda時,會強制轉換成LambdaExpression
並傳入VisitLambda方法中:
protected virtual Expression VisitLambda(LambdaExpression lambda) { Expression body = this.Visit(lambda.Body); if (body != lambda.Body) { return Expression.Lambda(lambda.Type, body, lambda.Parameters); } return lambda; }
事實上,這段代碼不用太過理解其它部份,只須要知道:
當Expression的NodeType == ExpressionType.Lambda時,是能夠顯示轉換成:LambdaExpression的。
而且它有一個叫Body的屬性:(獲取 lambda 表達式的主體。),以及一個叫Parameters的屬性:(獲取 lambda 表達式的參數。)
Body返回的是LambdaExpression的主體。
主體:指在LambdaExpression中的主要結構,或者說主要表達式。好比紅色標記部份的:
o => o.ID != 1 && (o.UserName == "steden" || o.UserName == "farseer.net")
而Parameters的返回的是參數表達式樹(出現了一個新名詞,下篇會詳細講解)。這裏簡單的講解:上面出現的o 便是參數,o的類型是UserVO
接着上面的:VisitLambda方法裏繼續訪問:this.Visit(lambda.Body),也就是解析主體部份。
從上面的表達式代碼(紅色部份),它會執行:this.VisitBinary((BinaryExpression)exp);方法。
在這裏知道BinaryExpression(表示包含二元運算符的表達式。)是對於上面的&&的解析就足夠了。
在上篇咱們強調了Expression是一種數據結構,也就是說紅色部份,咱們定義的代碼實質是被保存成一種數據結構的,如圖:
紅色底是:BinaryExpression類型(表示包含二元運算符的表達式。)二元運算,好比 && || >= < !=
藍色底是:ParameterExpression類型(表示命名的參數表達式。)傳入的參數,好比UserVO實體類
綠色底是:ConstantExpression類型(表示具備常量值的表達式。)具體的常量值。
因爲太晚了,這篇末尾的動態構造,放到下一篇中