在C#我們可以自定義委托,但是C#為什么還要內(nèi)置泛型委托呢?因為我們常常要使用委托,如果系統(tǒng)內(nèi)置了一些你可能會用到的委托,那么就省去了定義委托,然后實例化委托的步驟,這樣一來既使代碼看起來簡潔而干凈又能提高程序員的開發(fā)速度,何樂不為呢!通過本文可以讓你復習擴展方法,同時可以循序漸進的了解系統(tǒng)內(nèi)置泛型委托的實現(xiàn)以及委托逐步的演化過程。
定義:"Lambda表達式"是一個匿名函數(shù),是一種高效的類似于函數(shù)式編程的表達式
好處:Lambda簡化了匿名委托的使用,減少開發(fā)中需要編寫的代碼量。
具體內(nèi)容:它可以包含表達式和語句,并且可用于創(chuàng)建委托或表達式目錄樹類型,支持帶有可綁定到委托或表達式樹的輸入?yún)?shù)的內(nèi)聯(lián)表達式。
寫法:所有Lambda表達式都使用Lambda運算符=>,該運算符讀作"goes to"。Lambda運算符的左邊是輸入?yún)?shù)(如果有),右邊是表達式或語句塊。Lambda表達式x => x * x讀作"x goes to x times x"。
接下來從例子中慢慢學習:
namespace LambdaLearn { public class Person { public string Name { get; set; } public int Age { get;set; } } class Program { public static List<Person> PersonsList()//方法返回Person類的List集合 { List<Person> persons = new List<Person>(); for (int i = 0; i < 7; i++) { Person p = new Person() { Name = i + "人物年齡", Age = 8 - i, }; persons.Add(p); } return persons; } static void Main(string[] args) { List<Person> persons0 = PersonsList(); List<Person> persons1 = persons.Where(p => p.Age > 6).ToList(); //所有Age>6的Person的集合 Person per = persons.SingleOrDefault(p => p.Age == 1); //Age=1的單個people類 List<Person> persons2 = persons.Where(p => p.Name.Contains("年齡")).ToList(); //所有Name包含年齡的Person的集合 } } }
從例一可以看出一點lambda表達式的簡單用法,接著往下看。
Lambda簡化了匿名委托的使用,我們可以看一看下面例子怎樣簡化的。如果委托與事件不是很懂請看:
http://theartemis.cn/article/24416
例二:用lambda表達式簡化委托
利用委托處理方法:
//委托 逛超市 delegate int GuangChaoshi(int a); static void Main(string[] args) { GuangChaoshi gwl = JieZhang; Console.WriteLine(gwl(10) + ""); //打印20,委托的應用 Console.ReadKey(); } //結賬 public static int JieZhang(int a) { return a + 10; }
利用lambda表達式處理方法:
//委托 逛超市 delegate int GuangChaoshi(int a); static void Main(string[] args) { // GuangChaoshi gwl = JieZhang; GuangChaoshi gwl = p => p + 10; Console.WriteLine(gwl(10) + ""); //打印20,表達式的應用 Console.ReadKey(); }
委托跟表達式的兩段代碼,我們應該能明白了:其實表達式(p => p + 10;)中的 p 就代表委托方法中的參數(shù),而表達式符號右邊的 p+10,就是委托方法中的返回結果。
再看一個稍微復雜一點的例子:
//委托 逛超市 delegate int GuangChaoshi(int a,int b); static void Main(string[] args) { GuangChaoshi gwl = (p,z) => z-(p + 10); Console.WriteLine(gwl(10,100) + ""); //打印80,z對應參數(shù)b,p對應參數(shù)a Console.ReadKey(); }
[code]csharpcode:
/// <summary> /// 委托 逛超市 /// </summary> /// <param name="a">花費</param> /// <param name="b">付錢</param> /// <returns>找零</returns> delegate int GuangChaoshi(int a,int b); static void Main(string[] args) { GuangChaoshi gwl = (p, z) => { int zuidixiaofei = 10; if (p < zuidixiaofei) { return 100; } else { return z - p - 10; } }; Console.WriteLine(gwl(10,100) + ""); //打印80,z對應參數(shù)b,p對應參數(shù)a Console.ReadKey(); }
接下來看一下lambda的具體寫法形式:隱式表達即沒有指定參數(shù)類型(因為編譯器能夠根據(jù)上下文直接推斷參數(shù)的類型)
(x, y) => x * y //多參數(shù),隱式類型=>表達式 x => x * 5 //單參數(shù),隱式類型=>表達式 x => { return x * 5; } //單參數(shù),隱式類型=>語句塊 (int x) => x * 5 //單參數(shù),顯式類型=>表達式 (int x) => { return x * 5; } //單參數(shù),顯式類型=>語句塊 () => Console.WriteLine() //無參數(shù)
看完以上內(nèi)容,理解lambda表達式已經(jīng)不會有太大問題了,接下來的內(nèi)容稍微會深一點(至少我理解了很久Orz...)
簡單了解一下lambda背景:
Lambda 用在基于方法的 LINQ 查詢中,作為諸如 Where 和 Where 等標準查詢運算符方法的參數(shù)。
使用基于方法的語法在 Enumerable 類中調用 Where 方法時(像在 LINQ to Objects 和 LINQ to XML 中那樣),參數(shù)是委托類型 System..::.Func<(Of <(T, TResult>)>)。使用 Lambda 表達式創(chuàng)建委托最為方便。例如,當您在 System.Linq..::.Queryable 類中調用相同的方法時(像在 LINQ to SQL 中那樣),則參數(shù)類型是 System.Linq.Expressions..::.Expression<Func>,其中 Func 是包含至多五個輸入?yún)?shù)的任何 Func 委托。同樣,Lambda 表達式只是一種用于構造表達式目錄樹的非常簡練的方式。盡管事實上通過 Lambda 創(chuàng)建的對象的類型是不同的,但 Lambda 使得 Where 調用看起來類似。
背景這種想要深入研究的可以都了解一下,本文只是幫助了解lambda,這里就不多說了。
下列規(guī)則適用于 Lambda 表達式中的變量范圍:
捕獲的變量將不會被作為垃圾回收,直至引用變量的委托超出范圍為止。
在外部方法中看不到 Lambda 表達式內(nèi)引入的變量。
Lambda 表達式無法從封閉方法中直接捕獲 ref 或 out 參數(shù)。
Lambda 表達式中的返回語句不會導致封閉方法返回。
Lambda 表達式不能包含其目標位于所包含匿名函數(shù)主體外部或內(nèi)部的 goto 語句、break 語句或 continue 語句。
Lambda表達式的本質是“匿名方法”,即當編譯我們的程序代碼時,“編譯器”會自動將“Lambda表達式”轉換為“匿名方法”,如下例:
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方法的反編譯代碼如下:
string[]findNameA=Array.FindAll<string>(names,delegate(stringv){returnv.StartsWith("a");}); string[]findNameB=Array.FindAll<string>(names,delegate(stringv){returnv.StartsWith("a");});
Lambda表達式的語法格式:
參數(shù)列表 => 語句或語句塊
其中“參數(shù)列”中可包含任意個參數(shù)(與委托對應),如果參數(shù)列中有0個或1個以上參數(shù),則必須使用括號括住參數(shù)列,如下:
() => Console.Write("0個參數(shù)")
I => Console.Write("1個參數(shù)時參數(shù)列中可省略括號,值為:{0}",i)
(x,y) => Console.Write("包含2個參數(shù),值為:{0}*{1}",x,y)
而“語句或語句塊”中如果只有一條語句,則可以不用大括號括住否則必須使用,如下:
I => Console.Write("只有一條語句")
I => { Console.Write("使用大括號的表達式"); }
//兩條語句時必須要大括號
I => { i++;Console.Write("兩條語句的情況"); }
如果“語句或語句塊”有返回值時,如果只有一條語句則可以不輸寫“return”語句,編譯器會自動處理,否則必須加上,如下示例:
“Lambda表達式”是委托的實現(xiàn)方法,所以必須遵循以下規(guī)則:
1)“Lambda表達式”的參數(shù)數(shù)量必須和“委托”的參數(shù)數(shù)量相同;
2)如果“委托”的參數(shù)中包括有ref或out修飾符,則“Lambda表達式”的參數(shù)列中也必須包括有修飾符;
如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會為你解答??! 點擊進入論壇