說說lambda表達式與表達式樹(未完)

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;
    }
  }

 

解析一個表達式樹的例子
相關文章
相關標籤/搜索