1. 程式人生 > >lambda表達式和表達式樹(深入理解c#)

lambda表達式和表達式樹(深入理解c#)

來看 情況下 parameter 成員 表示 3.5 multi ret 委托

1.Lambda形式

1). Lambda表達式最冗長的形式:

(顯式類型的參數列表)=>{語句}

2). 大多數時候,都可以用一個表達式來表示主體,該表達式的值是Lambda的結果,在這些情況下,可以指定那個表達式,不使用大括號,不使用return語句,也不添加分號。

(顯式類型的參數列表)=> 表達式

3). 編譯器大多時候都能猜出參數類型,不需要你顯式聲明他們(隱式類型的參數列表就是一個以逗號分隔的名稱列表,沒有類型,但隱式和顯式類型的參數不能混合匹配——要麽全是隱式的,要麽全是顯式的)

(隱式類型的參數列表) => 表達式

4). 如果Lambda表達式只需一個參數,而且那個參數可以隱式指定類型,c#3允許省略圓括號。

參數名 => 表達式

2. 高階函數

Lambda表達式的主體本身可以包含另一個Lambda表達式,但做起來就像聽起來一樣,很容易讓人混淆,另外,Lambda表達式的參數可以是另一個委托,這樣做同樣很亂。

3. 表達式樹

.Net3.5的表達式樹提供了一種抽象方式將一些代碼表示成一個對象樹,c#3對於將Lambda表達式轉換成表達式樹提供了內建的支持。顧名思義,它們是對象構成的樹,樹中的每個節點本身就是一個表達式,不同的表達式類型代表能在代碼中執行的不同操作。

System.Linq。Expressions命名空間包含了代表表達式的各個類,它們都繼承自Expession,一個抽象的主要包含一些靜態工廠方法的類,這些方法用於創建其他表達式類的實例。然而Expression也包括兩個屬性

1)Type屬性代表表達式求值後的.Net類型,可把他視為一個返回了類型,例如,如果一個表達式要獲取一個字符串的Length屬性,該表達式的類型就是int。

2)NodeType屬性返回所代表的表達式的種類。他是ExpessionType枚舉的成員,包括LessThan,Multiply和Invoke等。仍然使用上面的例子,對於myString.Length這個屬性訪問來說,其節點類型是MemberAccess。該屬性最重要的地方,是它能區分由相同的類表示不同種類的表達式。

4. 將表達式樹編譯成委托

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的結果。

5. 將c#Lambda表達式轉換成表達式樹

可以要求編譯器通過你的Lambda表達式構建一個表達式樹,在執行時創建Expression<TDelegate>的一個實例。

Expression<Func<int>> return5 = () => 5

限制:

並非所有Lambda表達式都能轉換成表達式樹。不能將帶有一個語句塊(即使只有一個return語句)的Lambda轉換成表達式樹——只對單個表達式進行求值的Lambda表達式才可以。表達式中還不能包含賦值操作,因為在表達式樹中表示不了這種操作。盡管.Net4擴展了表達式樹的功能,但只能轉換單一表達式這一限制仍然有效。(上述只是最常見的,還有很多)

代碼:

MethodInfo method = typeof(string).GetMethod("StartsWith", new[] {typeof(string) });

var target = Expression.Parameter( typeof(string) , "x");

var methodArg = Expression.Parameter( typeof(string) , "y");

Expression[] methodArgs = new[] {methodArg};

Expression call = Expression.Call( target,method,methodArgs);

var lambdaParamethers = new[] { target,methodArg};

var lambda = Expression.Lambda<Func<string,string,bool>>(call,lambdaParameters);

var compiled = lambda.Compile();

Console.WriteLine( compiled("First","Second" ));

Console.WriteLine( compiled("First","Fir" ));

lambda表達式和表達式樹(深入理解c#)