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

  • 相关阅读:
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十一)
    install ubuntu on Android mobile phone
    Mac OS, Mac OSX 与Darwin
    About darwin OS
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十)
    Linux下编译安装qemu和libvirt
    libvirt(virsh命令总结)
    深入浅出 kvm qemu libvirt
    自然语言交流系统 phxnet团队 创新实训 项目博客 (九)
    自然语言交流系统 phxnet团队 创新实训 项目博客 (八)
  • 原文地址:https://www.cnblogs.com/tntboom/p/3986139.html
Copyright © 2011-2022 走看看