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表達式提供了編譯時檢查的能力,而表達式樹可以將執行模型從你所需的邏輯中提取出來,提供了遠程執行代碼的能力。
在討論動態類型時,將看到更多關於動態語言運行時的內容。表達式樹是其架構的核心部分,他們具有三個特點對DIR特別有吸引力:
1)他們是不易變的,因此可以安全地儲存;
2)他們是可組合的,因此可以在簡單的塊中構建出復雜的行為;
3)他們可以編譯為委托,后者可以像平常那樣進一步JIT編譯為本地代碼。
DLR需要對如何處理不同的表達式做出決定,這些表達式會因不同的規則而發生變化。表達式樹允許將這些規則(和結果)轉換為代碼,這與你知道所有的規則和結果后,手工編寫代碼非常接近。這一概念異常強大,可以使動態代碼以驚人的速度執行。

