C#中的表達式樹的淺解

表達式樹能夠說是Linq的核心之一,爲何是Linq的核心之一呢?由於表達式樹使得c#再也不是僅僅能編譯成IL,咱們能夠經過c#生成一個表達式樹,將結果做爲一箇中間格式,在將其轉換成目標平臺上的本機語言。好比SQL。咱們經常使用的Linq to sql就是這樣生成SQL的。sql

表達式樹是.NET 3.5以後引入的,它是一個強大靈活的工具(好比用在LINQ中構造動態查詢)。c#

先來看看Expression類的API接口:數據結構

namespace System.Linq.Expressions
{
    //
    // 摘要:
    //     以表達式目錄樹的形式將強類型 lambda 表達式表示爲數據結構。此類不能被繼承。
    //
    // 類型參數:
    //   TDelegate:
    //     System.Linq.Expressions.Expression`1 表示的委託的類型。
    public sealed class Expression<TDelegate> : LambdaExpression
    {
        //
        // 摘要:
        //     將表達式樹描述的 lambda 表達式編譯爲可執行代碼,並生成表示該 lambda 表達式的委託。
        //
        // 返回結果:
        //     一個 TDelegate 類型的委託,它表示由 System.Linq.Expressions.Expression`1 描述的已編譯的 lambda 表達式。
        public TDelegate Compile();
        //
        // 摘要:
        //     生成表示 lambda 表達式的委託。
        //
        // 參數:
        //   debugInfoGenerator:
        //     編譯器用於標記序列點並批註局部變量的調試信息生成器。
        //
        // 返回結果:
        //     包含 lambda 的已編譯版本的委託。
        public TDelegate Compile(DebugInfoGenerator debugInfoGenerator);
        //
        // 摘要:
        //     建立一個與此表達式相似的新表達式,但使用所提供的子級。若是全部子級都相同,則將返回此表達式。
        //
        // 參數:
        //   body:
        //     結果的 System.Linq.Expressions.LambdaExpression.Body 屬性。
        //
        //   parameters:
        //     結果的 System.Linq.Expressions.LambdaExpression.Parameters 屬性。
        //
        // 返回結果:
        //     此表達式(若是未更改任何子級),或帶有更新的子級的表達式。
        public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters);
        protected internal override Expression Accept(ExpressionVisitor visitor);
    }
}

表達式樹的語法以下:ide

Expression<Func<type,returnType>> = (param) => lamdaexpresion;

例如:工具

Expression<Func<int, int, int>> expr = (x, y) => x+y;

咱們運行以上代碼,並在VS調試模似下查看這個表達式樹:spa

image

能夠看到表達式樹主要由下面四部分組成:debug

一、Body 主體部分 調試

二、Parameters 參數部分 code

三、NodeType 節點類型 blog

四、Lambda表達式類型

在上述代碼中,主體即爲:x+y,參數爲(x,y),NodeType爲Lambda表達式,返回值爲int

主體部分能夠是表達式,可是不能包含語句。例如:我定義一個委託,Lambda表達式能夠這樣寫

Func<int, int, int> func = (x, y) => x + y;

也能夠這樣寫:

Func<int, int, int> func = (x, y) => { return x + y; };

可是,在表達式樹種,只能用第一種寫法,若是使用第二種寫法編譯彙報錯誤:沒法將具備語句體的 lambda 表達式轉換爲表達式樹

除了上邊的寫法,表達式樹還有能夠這麼寫:

ParameterExpression pex1 = Expression.Parameter(typeof(int), "x");//第一個參數
ParameterExpression pex2 = Expression.Parameter(typeof(int), "y");//第二個參數

BinaryExpression bexp = Expression.Add(pex1, pex2);//加法

var lambdaExp = Expression.Lambda<Func<int, int, int>>(bexp, new ParameterExpression[] {pex1,pex2 });

VS調試模式下能夠看到兩種寫法生成的表達式樹是同樣的

將表達式樹編譯成委託

LambdaExpression是從Expression派生的類型。泛型類Expression<TDelegate>是從LambdaExpression派生的,其中泛型參數TDelegate必須是委託類型。

LambdaExpression有個Compile方法能建立恰當類型的一個委託。而Expression<TDelegate>的Compile方法返回TDelegate類型的委託。來看看下面的例子:

Expression<Func<int, int, int>> expr = (x, y) => x + y;

ParameterExpression pex1 = Expression.Parameter(typeof(int), "x");//第一個參數
ParameterExpression pex2 = Expression.Parameter(typeof(int), "y");//第二個參數

BinaryExpression bexp = Expression.Add(pex1, pex2);//主體,加法

//使用Expression.Lambda方法,建立一個委託類型已知的Expression
Expression<Func<int,int,int>> lambdaExp 
    = Expression.Lambda<Func<int, int, int>>(bexp, new ParameterExpression[] { pex1, pex2 });

Func<int,int,int> tDelegate = lambdaExp.Compile();//編譯成委託

Console.WriteLine(tDelegate(1, 3));

Console.Read();

咱們運行上面代碼,結果爲:4。咱們寫了一大堆代碼,本質上就是用表達式樹計算了1+3的結果。

相關文章
相關標籤/搜索