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


Lambda表達式可以轉換成為代碼(委托)或者數據(表達式樹)。若將其賦值給委托,則Lambda表達式將轉換為IL代碼;如果賦值給 Expression<TDelegate>,則構造出一顆表達式樹。表達式樹本質上來說就是一顆抽象語法樹(AST),也就是一段代碼經過 解析后用樹形來表達出這段代碼的意思。解釋器將在代碼優化和代碼生成的時候使用到AST。在.NET中,表達式樹就是C#編譯器解析lambda表達式的 結果。簡單來說,轉換成表達式樹以后,我們可以通過自己的解釋器解析表達式樹來按需求實現自己的邏輯。

比如想表達加法,用中文寫就是 “二大於一” ,用數學來表達就是 "2>1",我們想表達的抽象概念就是大於,和具體的形式無關。因此表達式樹中就有表示GreaterThan的一種Type,表達的就是這么一種 大於的抽象概念。它可以由編譯器把lambda表達式 ()=> 2>1 編譯成我們所需的表達式樹,然后我們再通過解析這個表達式樹,把抽象概念翻譯成我們所需的“二大於一”這種中文的具體形式。

有這么一個笑話,說的是三國版批評與自我批評

 ”關羽:我要批評張飛,平時說話聲音太大,雖然用意是關心將士溫飽,但說話的樣子很凶,不利於團結基層兵士。 張飛:我批評趙雲,身為大將,衣着太干凈、太鮮亮,看起來很驕傲。趙雲:我要批評關羽,你的赤兔馬違反了公務用馬管理辦法,屬於超豪華配備吧?關羽:X, 你TM懂不懂什么叫批評啊?會不會玩啊?“

用上面的例子來說,就是lambda表達式要表達的是“批評他人”這個意思,但是不同的人解讀“批評他人”是不同的。可以用訪問者模式來做到這一點。

 

C#中不是每個類型都能相加的,編譯器會報錯。但是我們表達的意思是兩種類型相加這一通用的概念,因此這時候就可以用表達式樹來表達這一種概念,來“繞過”編譯器限制。這是合理的。

我 們可以自定義對於表達式中相加Expression.Add的理解,也可以由C#編譯器按照它的理解來幫我們編譯成可執行的匿名函數。C#編譯器理解中並 不是每種類型都可以相加的,因此如果Expression.compile成Func類型函數那么在執行的時候就有可能會報Exception,比如 "The binary operator Add is not defined for the types 'System.String' and 'System.String'."

 

表達式樹的順序與遍歷……

編譯器可以由lambda表達式幫我們生成一顆表達式樹,我們接下來解決的就是要如何解析這個樹的問題。對於樹我們采用至頂向下的遍歷方式,借助訪問者模式去解析表達式樹。

 

表達式樹的生成

當編譯器看到某個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;
    }
  }

 

解析一個表達式樹的例子

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM