假設給我們一個泛型對象List<T>,T為int類型,要求我們使用該對象方法FindAll(Predicate<T> match)從中找出該List中的偶數,您如何??
說明一下:Predicate<T>是一個泛型委派,它的原型為public delegate bool Predicate<T>(T obj),該委託傳入一個T類型對象,經邏輯判斷後返回布爾值。
委託
可能您首先想到的是用委託實現,實現方法如下:
// 方法1
static void Method1()
{
// 建立List<int>對象
List < int > list = new List < int > ();
list.AddRange( new int [] { 1 , 2 , 3 , 4 , 5 , 6 });
// 定義一個委託
Predicate < int > callback = new Predicate < int > (IsEvenNumber);
// 執行FindAll方法,該方法使用傳入的委託callback來判斷列表中的整數是否為偶數
List < int > evenNumbers = list.FindAll(callback);
// 輸出
foreach ( int i in evenNumbers)
{
Console.Write( " {0: 0} " , i);
}
Console.WriteLine();
}
// 判斷傳入的整數是否為偶數
static bool IsEvenNumber( int i)
{
return i % 2 == 0 ;
}複製代碼
這個方法不錯,簡單、直觀,就是有些......,有些什嗎?代碼顯得有些累贅,我們僅僅是要執行“i % 2 == 0”這樣一個判斷語句,卻要為這一條語句專門定義一個方法和一個委託。如果該方法在別處根本未被使用,那有沒有什麼辦法省去它呢(當然不是真正的省去,編譯後,該方法其實還存在,我們的目的是至少不用讓咱們特意為這條語句輸入一個方法和一個委託)?這時,我們的匿名方法該登場啦!
匿名方法
看下面的代碼:
static void Method2()
{
// 建立List<int>對象
List < int > list = new List < int > ();
list.AddRange( new int [] { 1 , 2 , 3 , 4 , 5 , 6 });
// 建立匿名方法,並將其傳給FindAll方法
List < int > evenNumbers = list.FindAll
(
delegate ( int i)
{
return i % 2 == 0 ;
}
);
// 輸出
foreach ( int i in evenNumbers)
{
Console.Write( " {0: 0} " , i);
}
Console.WriteLine();
}複製代碼
上例中delegate ( int i) { return i % 2 == 0 ; }語句建立了一個內聯匿名方法的委託,並傳給FindAll用於判斷列表中的一個整數是否為偶數。相較於Method1,我們不用特意定義一個方法和一個委託,代碼是精減了不少,但看著是不是有些彆扭?這個匿名方法的原型是啥樣?
麼急,一點點來分析。(int i)就是咱們定義的匿名方法的參數列表,return後返回一個布爾值,這就是該方法的傳回值,這麼看來,咱們的內聯匿名方法的委託原型其實就是:
delegate bool 匿名(int i)
看起來眼熟啊!這不和Predicate<T>的原型public delegate bool Predicate<T>(T obj),T代入int類型後一樣嘛!耶,真巧啊!是啊,不巧不行啊,您定義的匿名方法原型如果不是這個樣的話,那編譯器就直接報錯啦!List<int>.FindAll方法可是要求傳入一個Predicate<T>的委託呢!
嗯,這麼說來,內聯匿名方法的委託定義文法是這個樣啦:
delegate (參數列表)
{
執行語句
}複製代碼
Lambda運算式
匿名方法的實現已經夠簡練了,還有啥更簡練的文法來實現嗎?啥?還要簡練?匿名方法的文法就夠暈乎了,還要咋個簡練法,有些BT吧!麼辦法,微軟就是這麼BT。咱們就來看看更BT的Lambda運算式吧。小二,上代碼:
static void Method3()
{
// 建立List<int>對象
List < int > list = new List < int > ();
list.AddRange( new int [] { 1 , 2 , 3 , 4 , 5 , 6 });
// 建立Lambda運算式並傳給FindAll方法
List < int > evenNumbers = list.FindAll
(
( int x) => { return x % 2 == 0 ; } // 注意這裡噢,這就是大名鼎鼎的Lambda運算式
);
// 輸出
foreach ( int i in evenNumbers)
{
Console.Write( " {0: 0} " , i);
}
Console.WriteLine();
}複製代碼
看到這行代碼了吧:(int x) => { return x % 2 == 0; }
這是個啥東西?Lambda運算式?對頭!
讓我們來分析一下Lambda運算式的文法:別的先不管,關注一下“=>”符號。Lambda運算式被該符號分為兩部分,符號的前半部分是參數列表,後半部分是執行語句,簡化一下就是這樣:
參數列表=>執行語句
眼熟不?嗯,好像、大概、似乎、肯定、因為、所以有點眼熟,對了,這結構不和匿名方法一個樣嗎?咱再回頭看看匿名方法的文法:
delegate(參數列表){執行語句}
看出來了吧,Lambda運算式就是匿名方法嘛!區別僅在於用“=>”符號隔開了參數列表和執行語句而已。這麼說來,語句(int x) => { return x % 2 == 0; }不過是為FindAll傳入了一個內聯匿名方法的委託,該方法的參數列表為(int x),返回一個布爾值。
至此,是不是值得慶祝一下?我們好像開始理解這個BT的Lambda運算式了,現在應該叫小二上二鍋頭了吧,我再也不想看這讓人暈乎的代碼了。不過,先別高興,微軟又說了,這還不是最簡練的!啥?這還不簡練?那你寫一個更簡練的看看?小二,再上一盤代碼:
static void Method4()
{
// 建立List<int>對象
List < int > list = new List < int > ();
list.AddRange( new int [] { 1 , 2 , 3 , 4 , 5 , 6 });
// 建立Lambda運算式並傳給FindAll方法
List < int > evenNumbers = list.FindAll
(
x => x % 2 == 0 // 看到這裡,是不是有些無語了
);
// 輸出
foreach ( int i in evenNumbers)
{
Console.Write( " {0: 0} " , i);
}
Console.WriteLine();
}複製代碼
?看看這個:
x=> x % 2 == 0
這是我們第二次看到Lambda運算式了,只要記著Lambda運算式的文法:(參數列表=>執行語句)就行了。x就是該式的參數列表,為啥x連個參數類型都沒有呢?因為編譯器知道咱們要傳入的方法原型是bool Predicate<int>(int obj),自動就認為參數x的類型為int類型。同理,編譯器也知道方法的傳回值為布爾型,執行語句(x % 2 == 0)就是一個布爾型運算式,所以,編譯器也認為咱們要返回的就是這個運算式了。最後Lambda運算式就像被扒光了衣服的小正太一樣,裸奔在咱們的代碼中了。嗯,很好,裸一裸更健康!
咱們的委託、匿名方法、Lambda運算式的演化之旅這樣結束了。不過,好像還有一個問題,如果咱們的匿名方法不帶參數,那Lambda應該怎麼寫?嗯,先別說答案,讓我想想,是不是這樣“()=>{執行語句}”?對啦,就是這樣!
剛接觸這種BT的Lambda運算式,真是有些討厭,這文法簡練到“祼奔”了,但時間長了,你會發現它實在是太強大了,你一定會愛上這BT的Lambda運算式的。
轉自http://www.cnblogs.com/swjm119/archive/2011/12/10/2283271.html
假設給我們一個泛型對象List<T>,T為int類型,要求我們使用該對象方法FindAll(Predicate<T> match)從中找出該List中的偶數,您如何??
說明一下:Predicate<T>是一個泛型委派,它的原型為public delegate bool Predicate<T>(T obj),該委託傳入一個T類型對象,經邏輯判斷後返回布爾值。
委託
可能您首先想到的是用委託實現,實現方法如下:
// 方法1
static void Method1()
{
// 建立List<int>對象
List < int > list = new List < int > ();
list.AddRange( new int [] { 1 , 2 , 3 , 4 , 5 , 6 });
// 定義一個委託
Predicate < int > callback = new Predicate < int > (IsEvenNumber);
// 執行FindAll方法,該方法使用傳入的委託callback來判斷列表中的整數是否為偶數
List < int > evenNumbers = list.FindAll(callback);
// 輸出
foreach ( int i in evenNumbers)
{
Console.Write( " {0: 0} " , i);
}
Console.WriteLine();
}
// 判斷傳入的整數是否為偶數
static bool IsEvenNumber( int i)
{
return i % 2 == 0 ;
}複製代碼
這個方法不錯,簡單、直觀,就是有些......,有些什嗎?代碼顯得有些累贅,我們僅僅是要執行“i % 2 == 0”這樣一個判斷語句,卻要為這一條語句專門定義一個方法和一個委託。如果該方法在別處根本未被使用,那有沒有什麼辦法省去它呢(當然不是真正的省去,編譯後,該方法其實還存在,我們的目的是至少不用讓咱們特意為這條語句輸入一個方法和一個委託)?這時,我們的匿名方法該登場啦!
匿名方法
看下面的代碼:
static void Method2()
{
// 建立List<int>對象
List < int > list = new List < int > ();
list.AddRange( new int [] { 1 , 2 , 3 , 4 , 5 , 6 });
// 建立匿名方法,並將其傳給FindAll方法
List < int > evenNumbers = list.FindAll
(
delegate ( int i)
{
return i % 2 == 0 ;
}
);
// 輸出
foreach ( int i in evenNumbers)
{
Console.Write( " {0: 0} " , i);
}
Console.WriteLine();
}複製代碼
上例中delegate ( int i) { return i % 2 == 0 ; }語句建立了一個內聯匿名方法的委託,並傳給FindAll用於判斷列表中的一個整數是否為偶數。相較於Method1,我們不用特意定義一個方法和一個委託,代碼是精減了不少,但看著是不是有些彆扭?這個匿名方法的原型是啥樣?
麼急,一點點來分析。(int i)就是咱們定義的匿名方法的參數列表,return後返回一個布爾值,這就是該方法的傳回值,這麼看來,咱們的內聯匿名方法的委託原型其實就是:
delegate bool 匿名(int i)
看起來眼熟啊!這不和Predicate<T>的原型public delegate bool Predicate<T>(T obj),T代入int類型後一樣嘛!耶,真巧啊!是啊,不巧不行啊,您定義的匿名方法原型如果不是這個樣的話,那編譯器就直接報錯啦!List<int>.FindAll方法可是要求傳入一個Predicate<T>的委託呢!
嗯,這麼說來,內聯匿名方法的委託定義文法是這個樣啦:
delegate (參數列表)
{
執行語句
}複製代碼
Lambda運算式
匿名方法的實現已經夠簡練了,還有啥更簡練的文法來實現嗎?啥?還要簡練?匿名方法的文法就夠暈乎了,還要咋個簡練法,有些BT吧!麼辦法,微軟就是這麼BT。咱們就來看看更BT的Lambda運算式吧。小二,上代碼:
static void Method3()
{
// 建立List<int>對象
List < int > list = new List < int > ();
list.AddRange( new int [] { 1 , 2 , 3 , 4 , 5 , 6 });
// 建立Lambda運算式並傳給FindAll方法
List < int > evenNumbers = list.FindAll
(
( int x) => { return x % 2 == 0 ; } // 注意這裡噢,這就是大名鼎鼎的Lambda運算式
);
// 輸出
foreach ( int i in evenNumbers)
{
Console.Write( " {0: 0} " , i);
}
Console.WriteLine();
}複製代碼
看到這行代碼了吧:(int x) => { return x % 2 == 0; }
這是個啥東西?Lambda運算式?對頭!
讓我們來分析一下Lambda運算式的文法:別的先不管,關注一下“=>”符號。Lambda運算式被該符號分為兩部分,符號的前半部分是參數列表,後半部分是執行語句,簡化一下就是這樣:
參數列表=>執行語句
眼熟不?嗯,好像、大概、似乎、肯定、因為、所以有點眼熟,對了,這結構不和匿名方法一個樣嗎?咱再回頭看看匿名方法的文法:
delegate(參數列表){執行語句}
看出來了吧,Lambda運算式就是匿名方法嘛!區別僅在於用“=>”符號隔開了參數列表和執行語句而已。這麼說來,語句(int x) => { return x % 2 == 0; }不過是為FindAll傳入了一個內聯匿名方法的委託,該方法的參數列表為(int x),返回一個布爾值。
至此,是不是值得慶祝一下?我們好像開始理解這個BT的Lambda運算式了,現在應該叫小二上二鍋頭了吧,我再也不想看這讓人暈乎的代碼了。不過,先別高興,微軟又說了,這還不是最簡練的!啥?這還不簡練?那你寫一個更簡練的看看?小二,再上一盤代碼:
static void Method4()
{
// 建立List<int>對象
List < int > list = new List < int > ();
list.AddRange( new int [] { 1 , 2 , 3 , 4 , 5 , 6 });
// 建立Lambda運算式並傳給FindAll方法
List < int > evenNumbers = list.FindAll
(
x => x % 2 == 0 // 看到這裡,是不是有些無語了
);
// 輸出
foreach ( int i in evenNumbers)
{
Console.Write( " {0: 0} " , i);
}
Console.WriteLine();
}複製代碼
?看看這個:
x=> x % 2 == 0
這是我們第二次看到Lambda運算式了,只要記著Lambda運算式的文法:(參數列表=>執行語句)就行了。x就是該式的參數列表,為啥x連個參數類型都沒有呢?因為編譯器知道咱們要傳入的方法原型是bool Predicate<int>(int obj),自動就認為參數x的類型為int類型。同理,編譯器也知道方法的傳回值為布爾型,執行語句(x % 2 == 0)就是一個布爾型運算式,所以,編譯器也認為咱們要返回的就是這個運算式了。最後Lambda運算式就像被扒光了衣服的小正太一樣,裸奔在咱們的代碼中了。嗯,很好,裸一裸更健康!
咱們的委託、匿名方法、Lambda運算式的演化之旅這樣結束了。不過,好像還有一個問題,如果咱們的匿名方法不帶參數,那Lambda應該怎麼寫?嗯,先別說答案,讓我想想,是不是這樣“()=>{執行語句}”?對啦,就是這樣!
剛接觸這種BT的Lambda運算式,真是有些討厭,這文法簡練到“祼奔”了,但時間長了,你會發現它實在是太強大了,你一定會愛上這BT的Lambda運算式的。