Lambda表達式
"Lambda表達式"是一個匿名函數,是一種高效的類似于函數式程式設計的表達式,Lambda簡化了開發中需要編寫的代碼量。它可以包含表達式和語句,并且可用于建立委托或表達式目錄樹類型,支援帶有可綁定到委托或表達式樹的輸入參數的内聯表達式。所有Lambda表達式都使用Lambda運算符=>,該運算符讀作"goes to"。Lambda運算符的左邊是輸入參數(如果有),右邊是表達式或語句塊。Lambda表達式x => x * x讀作"x goes to x times x"。可以将此表達式配置設定給委托類型,如下所示:
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
Lambda表達式Lambda表達式是由.NET 2.0演化而來的,也是LINQ的基礎,熟練地掌握Lambda表達式能夠快速地上手LINQ應用開發。
Lambda表達式在一定程度上就是匿名方法的另一種表現形式。為了友善對Lambda表達式的解釋,首先需要建立一個People類,示例代碼如下。
public class People
{
public int age { get; set; } //設定屬性
public string name { get; set; } //設定屬性
public People(int age,string name) //設定屬性(構造函數構造)
{
this.age = age; //初始化屬性值age
this.name = name; //初始化屬性值name
}
}
上述代碼定義了一個People類,并包含一個預設的構造函數能夠為People對象進行年齡和名字的初始化。在應用程式設計中,很多情況下需要建立對象的集合,建立對象的集合有利于對對象進行搜尋操作和排序等操作,以便在集合中篩選相應的對象。使用List進行泛型程式設計,可以建立一個對象的集合,示例代碼如下。
List<People> people = new List<People>(); //建立泛型對象
People p1 = new People(21,"guojing"); //建立一個對象
People p2 = new People(21, "wujunmin"); //建立一個對象
People p3 = new People(20, "muqing"); //建立一個對象
People p4 = new People(23, "lupan"); //建立一個對象
people.Add(p1); //添加一個對象
people.Add(p2); //添加一個對象
people.Add(p3); //添加一個對象
people.Add(p4); //添加一個對象
上述代碼建立了4個對象,這4個對象分别初始化了年齡和名字,并添加到List清單中。當應用程式需要對清單中的對象進行篩選時,例如需要篩選年齡大于20歲的人,就需要從清單中篩選,示例代碼如下。
//匿名方法
IEnumerable<People> results = people.Where
(delegate(People p) { return p.age > 20; });
上述代碼通過使用IEnumerable接口建立了一個result集合,并且該集合中填充的是年齡大于20的People對象。細心的讀者能夠發現在這裡使用了一個匿名方法進行篩選,因為該方法沒有名稱,通過使用People類對象的age字段進行篩選。
雖然上述代碼中執行了篩選操作,但是,使用匿名方法往往不太容易了解和閱讀,而Lambda表達式則更加容易了解和閱讀,示例代碼如下。
- IEnumerable<People> results = people.Where(People => People.age > 20);
上述代碼同樣傳回了一個People對象的集合給變量results,但是,其編寫的方法更加容易閱讀,從這裡可以看出Lambda表達式在編寫的格式上和匿名方法非常相似。其實,當編譯器開始編譯并運作時,Lambda表達式最終也表現為匿名方法。
使用匿名方法并不是建立了沒有名稱的方法,實際上編譯器會建立一個方法,這個方法對于開發人員來說是不可見的,該方法會将People類的對象中符合p.age>20的對象傳回并填充到集合中。相同地,使用Lambda表達式,當編譯器編譯時,Lambda表達式同樣會被編譯成一個匿名方法進行相應的操作,但是與匿名方法相比,Lambda表達式更容易閱讀,Lambda表達式的格式如下。
- (參數清單)=>表達式或語句塊
-
上述代碼中,參數清單就是People類,表達式或語句塊就是People.age>20,使用Lambda表達式能夠讓人很容易地了解該語句究竟是如何執行的,雖然匿名方法提供了同樣的功能,卻不容易被了解。相比之下,People => People.age > 20卻能夠很好地了解為"傳回一個年紀大于20的人"。其實,Lambda表達式并沒有什麼高深的技術,Lambda表達式可以看作是匿名方法的另一種表現形式。Lambda表達式經過反編譯後,與匿名方法并沒有什麼差別。
比較Lambda表達式和匿名方法,在匿名方法中,"("、")"内是方法的參數的集合,這就對應了Lambda表達式中的"(參數清單)",而匿名方法中"{"、"}"内是方法的語句塊,這對應了Lambda表達式中"=>"符号右邊的表達式或語句塊項。Lambda表達式也包含一些基本的格式,這些基本格式如下。
Lambda表達式可以有多個參數、一個參數,或者沒有參數。其參數類型可以隐式或者顯式。示例代碼如下:
-
(x, y) => x * y //多參數,隐式類型=> 表達式 x => x * 5 //單參數, 隐式類型=>表達式 x => { return x * 5; } //單參數,隐式類型=>語句塊 (int x) => x * 5 //單參數,顯式類型=>表達式 (int x) => { return x * 5; } //單參數,顯式類型=>語句塊 () => Console.WriteLine() //無參數
- (x, y) => x + y //多參數,隐式類型=> 表達式
Lambda表達式的主體可以是表達式也可以是語句塊,這樣就節約了代碼的編寫。
【例2-5】傳統方法,匿名方法和Lamdba表達式對比。
(1) 建立控制台應用程式LamdbaPrictice。
(2) 在程式中添加3個函數,這3個函數分别使用傳統的委托調用、使用匿名方法和Lamdba表達式方法完成同一功能,對比有什麼不同。代碼如下:
-
-
程式的運作結果如圖2-7所示。using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LambdaDemo { class Program { static void Main(string[] args) { Console.WriteLine("傳統的委托代碼示例:"); FindListDelegate(); Console.Write("\n"); Console.WriteLine("使用匿名方法的示例:"); FindListAnonymousMethod(); Console.Write("\n"); Console.WriteLine("使用Lambda的示例:"); FindListLambdaExpression(); } //傳統的調用委托的示例 static void FindListDelegate() { //先建立一個泛型的List類 List<string> list = new List<string>(); list.AddRange(new string[] { "ASP.NET課程","J2EE課程", "PHP課程", "資料結構課程" }); Predicate<string> findPredicate = new Predicate<string>(IsBookCategory); List<string> bookCategory = list.FindAll(findPredicate); foreach (string str in bookCategory) { Console.WriteLine("{0}\t", str); } } //謂詞方法,這個方法将被傳遞給FindAll方法進行書書籍分類的判斷 static bool IsBookCategory(string str) { return str.EndsWith("課程") ? true : false; } //使用匿名方法來進行搜尋過程 static void FindListAnonymousMethod() { //先建立一個泛型的List類 List<string> list = new List<string>(); list.AddRange(new string[] { "ASP.NET課程", "J2EE課程", "PHP課程", "資料結構課程" }); //在這裡,使用匿名方法直接為委托建立一個代碼塊,而不用去建立單獨的方法 List<string> bookCategory = list.FindAll (delegate(string str) { return str.EndsWith("課程") ? true : false; } ); foreach (string str in bookCategory) { Console.WriteLine("{0}\t", str); } } //使用Lambda來實作搜尋過程 static void FindListLambdaExpression() { //先建立一個泛型的List類 List<string> list = new List<string>(); list.AddRange(new string[] { "ASP.NET課程", "J2EE課程", "PHP課程", "資料結構課程" }); //在這裡,使用了Lambda來建立一個委托方法 List<string> bookCategory = list.FindAll((string str) => str.EndsWith("課程")); foreach (string str in bookCategory) { Console.WriteLine("{0}\t", str); } } } }
-
Lambda表達式 之 C# 圖2-7 運作結果