委托、匿名函数与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表达式中调用了,在匿名函数的委托被销毁前,该外部变量将一直存在,因此会统计出实际的比较次数。

相关文章
相关标签/搜索