由简单例子了解C#中的委托和Lambda表达式

最近一直在实习,觉得自己的基础还是不行,遇到复杂的代码还是很不容易理解,于是又重温了《C#本质论》,便写下了这篇笔记。

委托(delegate):允许像处理其他任何数据一样处理对方法的引用。

Lambda表达式:可以快速和简单地创建自定义委托。


委托

C/C++中允许程序员利用”函数指针“将对方法的引用作为实参传递给另一个方法。C#则使用委托提供了相同的功能。委托允许捕捉对方法的引用,并像传递其他对象那样传递这个引用,像调用其他方法那样调用这个被捕捉的方法。

来看下边这个冒泡排序

    class SimpleSort1
    {
        public static void BubbleSort(int[] items)
        {
            int i, j, temp;
            if (items == null)
            {
                return;
            }
            for (i = items.Length - 1; i >= 0; i--)
            {
                for (j = 1; j <= i; j++)
                {
                    if (items[j - 1] > items[j])
                    {
                        temp = items[j - 1];
                        items[j - 1] = items[j];
                        items[j] = temp;
                    }
                }
            }
        }
    }

该方法实现了对整数数组的升序排列,但是如果我们现在想要升级或者降序来排列整数数组,就会有两个方案可以选择:1.复制上述代码,然后将 >操作符 改为 <操作符 。但是复制这么多代码知识改变了一个操作符,似乎不是很合理。2.传递一个附加参数,指出如何排序,看下边的代码。

class SimpleSort2
    {
        public enum SortType
        {
            Ascending,  //升序
            Descending  //降序
        }

        public static void BubbleSort(int[] items, SortType sortOrder)
        {
            int i, j, temp;
            if (items == null)
            {
                return;
            }

            for (i = items.Length-1; i >= 0; i--)
            {
                for (j = 1; j <= i; j++)
                {
                    bool swap = false;
                    switch (sortOrder)
                    {
                        case SortType.Ascending:
                            swap = items[j - 1] > items[j];
                            break;
                        case SortType.Descending:
                            swap = items[j - 1] < items[j];
                            break;
                    }
                    if (swap)
                    {
                        temp = items[j - 1];
                        items[j - 1] = items[j];
                        items[j] = temp;
                    }
                }
            }
        }
    }

通过传递第二个参数来判断是升序还是降序,但是上述代码也只是照顾了两种可能的排序方式,如果想要按照其他更多的方式进行排序,那么SortType值以及switch分支的数量将会变得很恐怖。

这个时候,为了增强灵活性和减少代码重复,可以将比较方法直接作为参数传递给BubbleSort()方法。为了能将方法作为参数传递,必须要有一个能够表示方法的数据类型。这就是大名鼎鼎的委托,因为它委托调用对象所引用的方法,来看下边的代码。本例中委托的数据类型是ComparisonHandler。

//声明一个委托类型
    public delegate bool ComparisonHandler(int first, int second);

    class DelegateSample
    {
        public static void BubbleSort(int[] items, ComparisonHandler comparisonMethod)
        {
            int i, j, temp;

            if (comparisonMethod == null)
            {
                throw new ArgumentNullException("comparisonMethod");
            }

            if (items == null)
            {
                return;
            }

            for (i = items.Length - 1; i >= 0; i--)
            {
                for (j = 1; j <= i; j++)
                {
                    if (comparisonMethod(items[j - 1], items[j]))
                    {
                        temp = items[j - 1];
                        items[j - 1] = items[j];
                        items[j] = temp;
                    }
                }
            }
        }

        //声明一个与委托类型兼容的方法(参数和返回值必须兼容委托的签名)
        public static bool GreaterThan(int first, int second)
        {
            return first > second;
        }

        static void Main()
        {
            int i;
            int[] items = new int[5];
            for (i = 0; i < items.Length; i++)
            {
                Console.WriteLine("Enter an integer: " );
                items[i] = int.Parse(Console.ReadLine());
            }

            BubbleSort(items, GreaterThan);
            for (i = 0; i < items.Length; i++)
            {
                Console.WriteLine(items[i]);
            }
        }
    }

你也可以通过改变BubbleSort()的第二个参数(声明另一个与委托类型兼容的方法),来改变排序方式。与文章开头的方法相比,现在的方法要简单许多。

如果你将委托声明在DelegateSample或者另一个类的内部,那么委托类型就会成为嵌套类型。

注意,ComparisonHandler委托是引用类型,但是你不必用new关键字去实例化它。从C#2.0开始,从方法组(为方法命名的表达式)向委托类型的转换会自动创建一个新的委托对象。


Lambda表达式

在上边的代码中。我们注意到了GreaterThan方法的声明(public static bool GreaterThan(int first, int second))比主体( return first > second;)复杂多了,这么简单的方法还需要这么复杂的准备,目的竟然只是为了转换为委托类型,显然不合适。

为了解决这个问题,C#2.0引入了非常精简的语法创建委托(匿名函数),C#3.0则更加精简(Lambda表达式),两种语法统称为匿名函数(anonymous function)。我们应该优先使用Lambda表达式。

Lambda表达式的目的在于需要基于很简单的方法生成委托时,避免声明全新成员的麻烦,来看下边的代码

BubbleSort(items, (int first, int second) => {return first < second;});

上述代码可以将BubbleSort()的第2个参数理解为”整数first和second用于返回first<second的结果“。和之前的调用相比,围绕方法的准备工作大大减少了。然而,语法还是有些长,从委托类型就可以推断出Lambda表达式必然返回bool,同样可以推断出两个参数必然是int类型,看下边的代码

BubbleSort(items, (first, second) => {return first < second;});

通常,只要编译器能从Lambda表达式所转换成的委托推断出类型,所有Lambda表达式都不需要显式声明参数类型。然而,若指定类型能使代码更易读,C#也允许这样做。在不能推断出类型的情况下,C#要求显式地指定Lambda參数类型。只要显式指定了一个Lambda参数类型,所有参数类型都必须被显式指定,而且必须和委托参数类型完全一致。

当然你也可以使用更简单的表达式Lambda来传递委托

BubbleSort(items, (first, second) => first < second);

在阅读上述代码时,可以理解为“first和second满足frst小于second的条件”。

下表总结了Lambda表达式的注意事项:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值