委託、匿名函數與Lambda表達式初步

(如下內容主要來自《C#本質論第三版》第十二章委託和Lambda表達式)數組

1、委託續函數

上上週五看了看委託,初步明白了其是個什麼,如何定義並調用。上週五準備看Lambda表達式,結果發現C#本質論中順帶講了講委託,因此在這,繼續寫一下委託。spa

首先,考慮以下問題:.net

須要對一個數組排序,先假設是數字,要求由大到小,很快咱們便想到了冒泡排序code

 1   public static void bubblSort(int[] items)
 2         {
 3             int i, j, temp;
 4             if (items == null)
 5             {
 6                 throw new ArgumentNullException("錯誤");
 7             }
 8             for (i = items.Length - 1; i >= 0; i--)
 9             {
10                 for (j = 1; j <= i; j++)
11                 {
12                     if (items[j - 1]<items[j])
13                     {
14                         temp = items[j - 1];
15                         items[j - 1] = items[j];
16                         items[j] = temp;
17                     }
18                 }
19             }
20         }

顯然,能夠從大到小對數組進行排序,可是此時,咱們要求對數組從大到小或者從小到大選擇,也很簡單,多寫一個Switch就好了,以下:blog

 1   public static void bubblSort(int[] items, string style )
 2         {
 3             int i, j, temp;
 4             if (items == null)
 5             {
 6                 throw new ArgumentNullException("錯誤");
 7             }
 8             for (i = items.Length - 1; i >= 0; i--)
 9             {
10                 for (j = 1; j <= i; j++)
11                 {
12                     switch(style)
13                     {
14                         case "big":
15                             if (items[j - 1]<items[j])
16                             {
17                                 temp = items[j - 1];
18                                 items[j - 1] = items[j];
19                                 items[j] = temp;
20                             }
21                             break;
22                         case "little":
23                             if (tems[j - 1]<items[j])
24                             {
25                                 temp = items[j - 1];
26                                 items[j - 1] = items[j];
27                                 items[j] = temp;
28                             }
29                     }          
30                 }
31             }
32         }

如此,我要是傳入一串字符數組,而後按拼音排序呢,能夠繼續寫Case語句,可是很明顯,這樣下去代碼很臃腫。通過分析發現,關鍵就在於If語句裏面的那個條件,若是我能將這個條件做爲一個可變的就行了。排序

而具體判斷呢,我能夠寫成一個一個的函數,到時候把這個函數傳進來就好了,因而想到了委託,我能夠定義一個以下類型的委託:編譯器

  public delegate bool ComparisonHandler(int first, int second);

這樣,經過控制什麼時候返回真,即可以選擇想要的排序類型了。string

例如控制由大到小排序的函數以下:it

   public static bool LessTan(int first, int second)//將他傳入委託,那麼就是降序排序
        {
            return first < second;
        }

BubbleSort函數改爲以下形式:

 1    public static void bubblSort(int[] items, ComparisonHandler comparisonhandler)
 2         {
 3             int i, j, temp;
 4             if (items == null)
 5             {
 6                 throw new ArgumentNullException("comparisonhandler");
 7             }
 8             for (i = items.Length - 1; i >= 0; i--)
 9             {
10                 for (j = 1; j <= i; j++)
11                 {
12                     if (comparisonhandler(items[j - 1], items[j]))//即判斷是大是小以及判斷規則,均有此委託指定,只要保證返回的bool類型符合規定便可
13                     {
14                         temp = items[j - 1];
15                         items[j - 1] = items[j];
16                         items[j] = temp;
17                     }
18                 }
19             }
20         }

能夠看出,BubbleSort函數第二個參數是剛纔定義的委託類型,那麼當作以下調用的時候:

bubblSort(items,LessTan);

if語句會根據LessTan函數的返回值判斷是否執行。當更改了LessTan函數體中的返回值的條件時(或者編寫新的判斷返回值的函數),即可以選擇不一樣的排序方式了。

注:.net2.0之後,委託做爲參數傳入能夠直接用相同簽名的函數做爲實參,而不須要實例化,實例化以下寫:

bubblSort(items,new ComparisonHanlder(LessTan));

如今已經不須要這種寫法。

2、匿名方法

咱們由上文可知,BubbleSort接受了一個委託類型(實參爲與委託有相同簽名的函數),其實能夠不寫一個函數,而將LessTan寫成以下形式:

 //降序,我沒有用委託調用LessThan,而是使用了匿名方法,固然在有參可是功能裏不要參數的時候,能夠省略參數列表,可是不推薦。
            bubblSort(items, delegate(int first, int second) { return first < second; });

直接定義委託類型(這樣說欠妥),而不寫出任何名字,直接寫參數列表與函數體,這樣也能夠傳入BubbleSort,這就是通常的匿名函數的寫法。

匿名函數的參數與返回值也要與其對應的委託類型一致。

固然,在一些狀況下能夠把參數省略:

 //降序,我沒有用委託調用LessThan,而是使用了匿名方法,固然在有參可是功能裏不要參數的時候,能夠省略參數列表,可是不推薦。
            bubblSort(items, delegate{ return Console.WriteLine("!!"));

這樣系統會自動匹配參數,可是特別不推薦這種寫法。

 3、Lambda表達式

Lambda表達式是C#3.0引進的 比匿名方法更加簡潔的一種匿名函數語法,我能夠不寫Delegate了。可是要寫看起來高大上的=>了。

例如匿名函數改爲以下代碼:

//語句Lambda
            //還能夠用Lambda表達式書寫更加簡介的匿名函數
            bubblSort(items, (int first, int second) => { return first < second; });

能夠這麼讀這句話:first與second用於返回比較結果。 這一組語句叫作 語句Lambda,傳入Delegate類型的委託形參中,注意,變量與返回值要一致。

Lambda甚至能夠容許省略參數類型,只要你確保編譯器可以推斷出來類型,因此以上語句能夠改寫以下:

   //Lambda還能夠推斷類型,由於我定義的comparisonhandler的兩個參數是int類型,因此能夠再也不寫出類型,若是一個參數寫出了類型,剩下的也要都寫
            bubblSort(items, (first, second) => { compareCount++; return first < second; });

注意,即便沒有參數,Lambda表達式的左側也要寫()

剛纔那種寫法帶大括號,屬於語句Lambda。表達式Lambda只有一個表達式,寫法以下:

    //表達式Lambda寫法
            bubblSort(items, (first, second) =>  first < second);//語句有大括號組成的語句塊,而表達式在右側只有一個表達式

還有,當在表達式中調用外部變量的時候,我我的感受他被在執行的時候看成了靜態變量,例如上上句的compareCount是在主函數中定義的一個int類型,在Lambda表達式中調用了,在匿名函數的委託被銷燬前,該外部變量將一直存在,因此會統計出實際的比較次數。

相關文章
相關標籤/搜索