文章出處

摘自:"http://www.cnblogs.com/eagle1986/archive/2012/01/19/2327358.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表達式的。

 

 

 

 

 

----------------------------------------


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()