LAmbda表達式 C#版

                                                                         Lambda
“Lambda 表達式”(lambda expression)是一個匿名函數,Lambda表達式基於數學中的λ演算得名,直接對應於其中的lambda抽象(lambda abstraction),是一個匿名函數,即沒有函數名的函數。Lambda表達式可以表示閉包(注意和數學傳統意義上的不同)。
C#的Lambda 表達式都使用 Lambda 運算符 =>,該運算符讀爲“goes to”。語法如下:
形參列表=>函數體
函數體多於一條語句的可用大括號括起。

類型

可以將此表達式分配給委託類型,如下所示:
1
2
3
delegate int del(int i);
    del myDelegate = x=>{return x*x;};
    int j = myDelegate(5);//j=25
創建表達式目錄樹類型:
1
2
3
using System.Linq.Expressions;
//...
Expression <del>=x=>x*x;
=> 運算符具有與賦值運算符 (=) 相同的優先級,並且是右結合運算符。
Lambda 用在基於方法的 LINQ 查詢中,作爲諸如 Where 和 Where 等標準查詢運算符方法的參數。
使用基於方法的語法在 Enumerable 類中調用 Where 方法時(像在 LINQ to Objects 和 LINQ to XML 中那樣),參數是委託類型 System..::.Func<(Of <(T, TResult>)>)。使用 Lambda 表達式創建委託最爲方便。例如,當您在 System.Linq..::.Queryable 類中調用相同的方法時(像在 LINQ to SQL 中那樣),則參數類型是 System.Linq.Expressions..::.Expression<Func>,其中 Func 是包含至多五個輸入參數的任何 Func 委託。同樣,Lambda 表達式只是一種用於構造表達式目錄樹的非常簡練的方式。儘管事實上通過 Lambda 創建的對象的類型是不同的,但 Lambda 使得 Where 調用看起來類似。
在前面的示例中,請注意委託簽名具有一個 int 類型的隱式類型輸入參數,並返回 int。可以將 Lambda 表達式轉換爲該類型的委託,因爲該表達式也具有一個輸入參數 (x),以及一個編譯器可隱式轉換爲 int 類型的返回值。(以下幾節中將對類型推理進行詳細討論。)使用輸入參數 5 調用委託時,它將返回結果 25。
在 is 或 as 運算符的左側不允許使用 Lambda。
適用於匿名方法的所有限制也適用於 Lambda 表達式。有關更多信息,請參見匿名方法(C# 編程指南)。

特殊

下列規則適用於 Lambda 表達式中的變量範圍:
捕獲的變量將不會被作爲垃圾回收,直至引用變量的委託超出範圍爲止。
在外部方法中看不到 Lambda 表達式內引入的變量。
Lambda 表達式無法從封閉方法中直接捕獲 ref 或 out 參數。
Lambda 表達式中的返回語句不會導致封閉方法返回。
Lambda 表達式不能包含其目標位於所包含匿名函數主體外部或內部的 goto 語句、break 語句或 continue 語句。
Lambda表達式的本質是“匿名方法”,即當編譯我們的程序代碼時,“編譯器”會自動將“Lambda表達式”轉換爲“匿名方法”,如下例:
1
2
3
string[] names={"agen","balen","coure","apple"};
string[] findNameA=Array.FindAll<string>(names,delegate(string v){return v.StartsWith("a");});
string[] findNameB=Array.FindAll<string>(names,v=>v.StartsWith("a"));
上面中兩個FindAll方法的反編譯代碼如下:
1
2
string[]findNameA=Array.FindAll<string>(names,delegate(string v){return v.StartsWith("a");});
string[]findNameB=Array.FindAll<string>(names,delegate(string v){return v.StartsWith("a");});
從而可以知道“Lambda表達式”與“匿名方法”是可以劃上等號的,只不過使用“Lambda表達式”輸寫代碼看上去更直觀漂亮,不是嗎?
Lambda表達式的語法格式:
參數列表 => 語句或語句塊
其中“參數列”中可包含任意個參數(與委託對應),如果參數列中有0個或1個以上參數,則必須使用括號括住參數列,如下:
() => Console.Write("0個參數")
I => Console.Write("1個參數時參數列中可省略括號,值爲:{0}",i)
(x,y) => Console.Write("包含2個參數,值爲:{0}*{1}",x,y)
而“語句或語句塊”中如果只有一條語句,則可以不用大括號括住否則必須使用,如下:
I => Console.Write("只有一條語句")
I => { Console.Write("使用大括號的表達式"); }
//兩條語句時必須要大括號
I => { i++;Console.Write("兩條語句的情況"); }
如果“語句或語句塊”有返回值時,如果只有一條語句則可以不輸寫“return”語句,編譯器會自動處理,否則必須加上,如下示例:
“Lambda表達式”是委託的實現方法,所以必須遵循以下規則:
1)“Lambda表達式”的參數數量必須和“委託”的參數數量相同;
2)如果“委託”的參數中包括有ref或out修飾符,則“Lambda表達式”的參數列中也必須包括有修飾符;
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class    Test
{
    delegateintAddHandler(intx,inty);
    staticvoidPrint(AddHandleradd)
{
    Console.Write(add(1,3));
}
 
static void  Main()
{
    Print((x,y)=>x+y);
    Print((x,y)=>{intv=x*10;returny+v;});
    Console.Read();
}
}
注: 如果包括有修飾符,則“Lambda表達式”中的參數列中也必須加上參數的類型
3)如果“委託”有返回類型,則“Lambda表達式”的“語句或語句塊”中也必須返回相同類型的數據;
4)如果“委託”有幾種數據類型格式而在“Lambda表達式”中“編譯器”無法推斷具體數據類型時,則必須手動明確數據類型。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
classTest
{
delegateTAddHandler<T>(Tx,Ty);
 
static    void    Print(AddHandler<int>test)
{
Console.WriteLine("inttype:{0}",test(1,2));
}
 
static    void    Print(AddHandler<double>test)
{
Console.WriteLine("doubletype:{0}",test(1d,2d));
}
 
staticvoidMain()
{
Print((x,y)=>x+y);
Console.Read();
}
}
當我們編譯以下代碼時,編譯器將會顯示以下錯誤信息:
在以下方法或屬性之間的調用不明確:
“ConsoleApplication1.Test.Print(ConsoleApplication1.Test.AddHandler<int>)”和“ConsoleApplication1.Test.Print(ConsoleApplication1.Test.AddHandler<double>)”
所以我們必須明確數據類型給編譯器,如下:
1
Print((intx,inty)=>x+y);
這樣我們的代碼就能編譯通過了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章