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

时间: 2024-10-09 02:36:25

委托、匿名函数与Lambda表达式初步的相关文章

3 委托、匿名函数、lambda表达式

委托.匿名函数.lambda表达式 在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法.C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式 // 声明一个委托 delegate void Printer(string s); class TestClass { static void Main() { //lambda表达式 Printer pp = x => { Console.WriteLine(&quo

委托,匿名函数和lambda表达式

很早之前就接触到了委托,但是一直对他用的不是太多,主要是本人是菜鸟,能写的比较高级的代码确实不多,但是最近在看MSDN微软的类库的时候,发现了微软的类库好多都用到了委托,于是决定好好的研究研究,加深一下自己对他的印象,顺便把自己的感悟和想法写出来,以便自己能有更深的理解,由于本人水平有限,也欢迎大家多多探讨,有问题大家一起解决一起进步. MSDN上面对委托的定义是:delegate 是表示对具有特定参数列表和返回类型的方法的引用的类型.在我看来委托的特性主要在: 1.把一个方法当做一个参数传递给

C# 匿名函数和Lambda 表达式

匿名函数是一个"内联"语句或表达式,可在需要委托类型的任何地方使用. 可以使用匿名函数来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数. 共有两种匿名函数,以下主题中分别讨论了这些函数: Lambda Expressions (C# Programming Guide). ' data-guid="7df86c4348dea57abb774138a7de05b8">Lambda 表达式(C# 编程指南) . 匿名方法(C# 编程指南) 说明

C#语法之匿名函数和Lambda表达式

上一篇博客主要是对委托和事件做了一小结,这篇是在上一篇博客的基础上对匿名函数和Lambda表达式小结.还是接着上一篇说起,在上一篇中也说了委托是一种数据结构,主要是解决让函数作为参数的问题.在使用委托时首先要声明代理,然后实例化,并将委托对象和已定义好的函数关联上,最后调用.这里与已定义好的函数关联的事情,如果函数是经常使用的也还好,如果不是经常使用的可能只调用一次,那这岂不是老费劲了.就是能不能在使用的时候定义下呢?于是乎有了匿名方法. 一.匿名方法的使用. 匿名方法的使用步骤和委托的使用步骤

C#匿名委托,匿名函数,lambda表达式

一.类型.变量.实例之间的关系. 类型>变量>实例 类型可以创建变量,实体类可以创建实例,实例可以存储在变量里. 二.委托使用过程: 1.定义委托(写好签名): 2.创建委托变量: 3.在委托变量里放函数(相同的签名). 事件:用预先定义好的委托(EventHandle)的定义的变量(接收两个参数). 窗体里自带一个委托变量:我们做的就是给这个变量追加函数. 给窗体Load事件添加一个函数 public partial class Form1 : Form { public Form1() {

委托、匿名函数、Lambda表达式和事件的学习

委托: 还记得C++里的函数指针么?大家可以点击这里查看一下以前的笔记.C#的委托和C++中的函数指针效果一致. 当我们需要将函数作为对象进行传递和使用时就需要用到委托. 下面我们看一个例子: 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Test 8 { 9 cl

12_Python的(匿名函数)Lambda表达式_Python编程之路

Python作为一门高级语言,与很多编程语言一样都具有匿名函数这一特征 匿名函数,也就Lambda表达式,通俗来讲就是不用命名的方法,直接定义,直接用即可 创建匿名函数需要用到Lambda关键字,下面我们通过一个简单的匿名函数的创建熟悉匿名函数 lambda a,b : a + b 这个表达式返回的值是a加上b的值,他需要传入两个参数,也就是a,b,同时还需要一个表达式,这样才能构成一个完整的匿名函数 通过代码完善这一部分的理解 In [1]: func = lambda a,b : a+b I

C#委托、匿名方法和Lambda表达式

工作中经常用到Lambda表达式,简单好用代码清晰,虽然用的也算上手,但忘记了当年大学课堂上学它的时候老师讲的它跟委托和匿名方法的关系,今天抽了时间简单的了解了一下,在这里做个总结. 1 什么是委托 public delegate string DelegateTest(string a); public static string GetA(string a) { return a; } static void Main(string[] args) { DelegateTest d = ne

匿名方法,Lambda表达式,高阶函数

原文:匿名方法,Lambda表达式,高阶函数 匿名方法 c#2.0引入匿名方法,不必创建单独的方法,因此减少了所需的编码系统开销. 常用于将委托和匿名方法关联,例如 1. 使用委托和方法关联: this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);private void btnRefresh_Click(object sender, EventArgs e){    BindData();} 2. 使用委