zoukankan      html  css  js  c++  java
  • 委托、匿名函数与Lambda表达式初步

    (以下内容主要来自《C#本质论第三版》第十二章委托和Lambda表达式)

    一、委托续

    上上周五看了看委托,初步明白了其是个什么,如何定义并调用。上周五准备看Lambda表达式,结果发现C#本质论中顺带讲了讲委托,所以在这,继续写一下委托。

    首先,考虑如下问题:

    需要对一个数组排序,先假设是数字,要求由大到小,很快我们便想到了冒泡排序

     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就行了,如下:

     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);

    这样,通过控制何时返回真,便可以选择想要的排序类型了。

    例如控制由大到小排序的函数如下:

       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));

    现在已经不需要这种写法。

    二、匿名方法

    我们由上文可知,BubbleSort接受了一个委托类型(实参为与委托有相同签名的函数),其实可以不写一个函数,而将LessTan写成如下形式:

     //降序,我没有用委托调用LessThan,而是使用了匿名方法,当然在有参但是功能里不要参数的时候,可以省略参数列表,但是不推荐。
                bubblSort(items, delegate(int first, int second) { return first < second; });

    直接定义委托类型(这样说欠妥),而不写出任何名字,直接写参数列表与函数体,这样也可以传入BubbleSort,这就是一般的匿名函数的写法。

    匿名函数的参数与返回值也要与其对应的委托类型一致。

    当然,在一些情况下可以把参数省略:

     //降序,我没有用委托调用LessThan,而是使用了匿名方法,当然在有参但是功能里不要参数的时候,可以省略参数列表,但是不推荐。
                bubblSort(items, delegate{ return Console.WriteLine("!!"));

    这样系统会自动匹配参数,但是特别不推荐这种写法。

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

  • 相关阅读:
    Tomcat使用经验
    JAVA异常及其异常处理方式
    微信小程序开发笔记(七)--template模板
    微信小程序开发笔记(六)--实现tab选项卡
    微信小程序开发笔记(五)--swiper实现tab选项卡
    微信小程序开发笔记(四)--轮播图
    微信小程序开发笔记(三)--底部导航栏,顶部标题栏设置
    微信小程序开发笔记(二)
    微信小程序开发笔记(一)
    校门外的树
  • 原文地址:https://www.cnblogs.com/tntboom/p/3986139.html
Copyright © 2011-2022 走看看