Lambda表達式能夠轉換成爲代碼(委託)或者數據(表達式樹)。若將其賦值給委託,則Lambda表達式將轉換爲IL代碼;若是賦值給 Expression<TDelegate>,則構造出一顆表達式樹。表達式樹本質上來講就是一顆抽象語法樹(AST),也就是一段代碼通過 解析後用樹形來表達出這段代碼的意思。解釋器將在代碼優化和代碼生成的時候使用到AST。在.NET中,表達式樹就是C#編譯器解析lambda表達式的 結果。簡單來講,轉換成表達式樹之後,咱們能夠經過本身的解釋器解析表達式樹來按需求實現本身的邏輯。express
好比想表達加法,用中文寫就是 「二大於一」 ,用數學來表達就是 "2>1",咱們想表達的抽象概念就是大於,和具體的形式無關。所以表達式樹中就有表示GreaterThan的一種Type,表達的就是這麼一種 大於的抽象概念。它能夠由編譯器把lambda表達式 ()=> 2>1 編譯成咱們所需的表達式樹,而後咱們再經過解析這個表達式樹,把抽象概念翻譯成咱們所需的「二大於一」這種中文的具體形式。ide
有這麼一個笑話,說的是三國版批評與自我批評:函數
」關羽:我要批評張飛,平時說話聲音太大,雖然用意是關心將士溫飽,但說話的樣子很兇,不利於團結基層兵士。 張飛:我批評趙雲,身爲大將,衣着太乾淨、太鮮亮,看起來很驕傲。趙雲:我要批評關羽,你的赤兔馬違反了公務用馬管理辦法,屬於超豪華配備吧?關羽:X, 你TM懂不懂什麼叫批評啊?會不會玩啊?「優化
用上面的例子來講,就是lambda表達式要表達的是「批評他人」這個意思,可是不一樣的人解讀「批評他人」是不一樣的。能夠用訪問者模式來作到這一點。ui
C#中不是每一個類型都能相加的,編譯器會報錯。可是咱們表達的意思是兩種類型相加這一通用的概念,所以這時候就能夠用表達式樹來表達這一種概念,來「繞過」編譯器限制。這是合理的。this
我 們能夠自定義對於表達式中相加Expression.Add的理解,也能夠由C#編譯器按照它的理解來幫咱們編譯成可執行的匿名函數。C#編譯器理解中並 不是每種類型均可以相加的,所以若是Expression.compile成Func類型函數那麼在執行的時候就有可能會報Exception,好比 "The binary operator Add is not defined for the types 'System.String' and 'System.String'."url
表達式樹的順序與遍歷……spa
編譯器能夠由lambda表達式幫咱們生成一顆表達式樹,咱們接下來解決的就是要如何解析這個樹的問題。對於樹咱們採用至頂向下的遍歷方式,藉助訪問者模式去解析表達式樹。翻譯
表達式樹的生成code
當編譯器看到某個lambda表達式賦值給了類型爲Expression的變量的時候,就會將其編譯成對一系列工廠方法的調用,這些工廠方法將會在程序運行時動態的構造出表達式樹。
表達式樹將在程序運行時動態構造,不過一旦構造完成,則沒法被再次修改。
public abstract class QueryProvider : IQueryProvider { protected QueryProvider() { } IQueryable<S> IQueryProvider.CreateQuery<S>(Expression expression) { return new Query<S>(this, expression); } IQueryable IQueryProvider.CreateQuery(Expression expression) { Type elementType = TypeSystem.GetElementType(expression.Type); try { return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(elementType), new object[] { this, expression }); } catch (TargetInvocationException tie) { throw tie.InnerException; } } IQueryProvider.Execute<S>(Expression expression) { return (S)this.Execute(expression); } object IQueryProvider.Execute(Expression expression) { return this.Execute(expression); } public abstract string GetQueryText(Expression expression); public abstract object Execute(Expression expression); }
public class AmazonBookQueryProvider : QueryProvider { public override String GetQueryText(Expression expression) { AmazonBookQueryCriteria criteria; // Retrieve criteria criteria = new AmazonBookExpressionVisitor().ProcessExpression(expression); // Generate URL String url = AmazonHelper.BuildUrl(criteria); return url; } public override object Execute(Expression expression) { String url = GetQueryText(expression); IEnumerable<AmazonBook> results = AmazonHelper.PerformWebQuery(url); return results; } }