前言

在C#我们可以自定义委托,但是C#为什么还要内置泛型委托呢?因为我们常常要使用委托,如果系统内置了一些你可能会用到的委托,那么就省去了定义委托,然后实例化委托的步骤,这样一来既使代码看起来简洁而干净又能提高程序员的开发速度,何乐不为呢!通过本文可以让你复习扩展方法,同时可以循序渐进的了解系统内置泛型委托的实现以及委托逐步的演化过程。

Action

概念:封装一个方法,该方法具有五个参数并且不返回值。并且类型参数为逆变

下面我就自定义实现一个Action<T>无返回值的委托。我们同样定义一个Person类,似乎我随笔中永远都离不开Person的话题,哈哈!请看如下代码

    public class Person{        public string Name { get; set; }        public int Age { get; set; }        public bool Gender { get; set; }}

然后在控制台中通过 ForEach 方法模拟Action委托,先定义一个获得Person的列表GetList()

        static List<Person> GetList(){List<Person> list = new List<Person>() { new Person(){ Name = "花千骨     (女娲后人及妖神)",   Age = 12, Gender = false},            new Person(){ Name = "白子画     (长留尊上)",   Age = 13, Gender = true},            new Person(){ Name = "东方彧卿   (异朽阁主及蜀国大学士)", Age = 14, Gender = true},            new Person(){ Name = "轻水       (长留弟子)",     Age = 15, Gender = false},            new Person(){ Name = "孟玄朗     (蜀国皇帝及长留弟子)",   Age = 16, Gender = true}};            return list;}

因为我们知道在用委托时,有这样几个步骤:

(1)定义委托

(2)实例化委托

(3)将方法指针添加到实例化委托对象中

但是现在我们无需定义委托,已经有了内置委托,只需将其实例化即可,同时添加方法的指针一般是有明确的方法,如果我们只是临时的用方法,这时就可以派匿名方法上场了,所以上面三步就可以简化成两步。代码如下:

            var list = GetList();list.ForEach(new Action<Person>(                  delegate(Person p){Console.WriteLine(p.Name);}));

上述代码颇有点jQuery中Each的遍历方法的意味。结果打印出:

我们知道ForEach这个方法里面的的参数就是 Action<T> action ,所以我们可以直接进行如下简写

 list.ForEach(delegate(Person p) { Console.WriteLine(p.Name); });

其打印结果和上面是一样的。其代码可以继续进行更加的精简,不着急,我们循序渐进的来。

Predicate

概念:定义一组条件并确定指定对象是否符合这些条件的方法。返回值为bool类型,并且类型参数为逆变。

用到此泛型委托莫过于List中的 FindAll() 方法了,它就是从一个集合中根据条件筛选出一个新的集合出来。上节刚好学过扩展方法,我们可以自定义实现这个方法用扩展方法加在泛型集合List上根据  Predicate 委托的参数条件进行筛选。

static List<T> SelfDefineFindAll<T> (this List<T> list, Predicate<T> pre)   /*注意:既然是添加的扩展方法,在此例中控制台的Program也要声明为静态类*/{List<T> preList = new List<T>; /*根据条件筛选出的数据添加到该集合中*/    foreach (T t in list){            if (pre(t)) /*根据条件进行筛选*/{preList.Add(t);}}      return preList;
}

我们查询出年纪大于13岁的并且根据ForEach来遍历筛选出来的数据,代码如下:

 var list = GetList(); var preList = list.SelfDefineFindAll(delegate(Person p) { return p.Age > 13; });preList.ForEach(delegate(Person p) { Console.WriteLine(p.Name); });

结果打印出正确的结果,如下:

而通过C#中的FindAll,则只需如下做即可同样达到上述的效果,只是不是扩展方法罢了:

list.FindAll(delegate(Person p) { return p.Name});

上述代码其实可以更加精简,不着急,我们一步一步循序渐进的来。

Comparison

概念:表示比较同一类型的两个对象的方法。参数类型为逆变,返回值为int。

 list.Sort(new Comparison<Person>(delegate(Person p, Person p1) { return p.Age - p1.Age; }));  /*年龄按照从小到大顺序排列*/

同样可以简写为:

 list.Sort((delegate(Person p, Person p1) { return p.Age - p1.Age; }));

Func

貌似在系统内置泛型委托中Func在实际项目开发中是使用的最多的。

概念:封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。参数类型为逆变,返回值参数类型为协变。

用到此委托的最多的就是List泛型集合中的 Select 方法了,看看内置的Select方法是如何利用Func来实现返回一个新的集合的。

(1)结合匿名方法实现

我们接下来在上面基础上再定义一个Animal类。属性和Person类一样,代码如下:

    public class Animal{        public string Name { get; set; }        public int Age { get; set; }        public bool Gender { get; set; }}

接下来我们就通过Select方法通过Person的集合来返回一个新的集合即Animal集合。代码如下:

            var list = GetList();List<Animal> animalList = list.Select(new Func<Person, Animal>(delegate(Person p){                return new Animal() { Name = p.Name, Age = p.Age, Gender = p.Gender };})).ToList();animalList.ForEach(delegate(Animal animal) { Console.WriteLine(animal.Name); });

同样打印出当遍历Person集合时的结果一样,看起来似乎很繁琐,我们将代码通过进行精简如下:

            var list = GetList();List<Animal> animalList = list.Select((delegate(Person p){                return new Animal() { Name = p.Name, Age = p.Age, Gender = p.Gender };})).ToList();animalList.ForEach(delegate(Animal animal) { Console.WriteLine(animal.Name); });

下面我们通过扩展方法来自定义实现Select()方法,代码如下:

        public static List<TR> SelfDefineSelect<T, TR>(this List<T> list, Func<T, TR> fun)/*T为传进来的泛型集合类型,TR为返回的泛型集合类型*/{List<TR> selList = new List<TR>();  /*实例化返回的泛型集合*/            foreach (T t in list){TR tr = fun(t);  /*获取传进来的集合数据*/selList.Add(tr);}            return selList;  /*返回新的泛型集合*/}

依然是进行此调用,打印结果正确:

            List<Animal> animalList = list.SelfDefineSelect((delegate(Person p){                return new Animal() { Name = p.Name, Age = p.Age, Gender = p.Gender };})).ToList();

(2)结合匿名类来实现

当我们使用Func根据条件转换成新的集合时可能只需要几个实例成员,这个时候如果还重新建立一个类来进行获取就显得有点小题大做了,这个时候只需将其需要的或的成员传给一个匿名类即可,这个就是Func需要用到匿名类的场景。所以鉴于此,我们将返回的新的集合为匿名集合而非Animal集合,代码改造如下:

            var anyousList = list.Select((delegate(Person p){                return new { Name = p.Name}; /*结合匿名类使用*/}));

通过上述所讲系统内置泛型委托的实现,似乎有点不太令人满意,关于委托的代码太过繁琐,是的微软大大也明确知道了这点,于是乎,一步一步走向了高级,那就下文的lambda表达式,这结构的简单简直了。。。让你爽到暴。

lambda表达式

上述代码说过可以精简,如何精简呢?那就是lambda表达式,匿名方法已经够简洁的了,但是lambda表达式是比匿名方法更加简洁的一种语法!我们用lambda表达式来分别实现上述中的Action、Predicate以及Func委托。

Action

            var list = GetList();list.ForEach(d => Console.WriteLine(d.Name);)

Predicate

            var list = GetList();list.FindAll(d => d.Age > 13);

Func

            list.Select(d =>  Person() { Name = d.Name, Age = d.Age, Gender ==>  { Name = d.Name});

好了,一切都变得如此明朗。自从有了lambda表达式,敲代码的速度加快了,妈妈再也不用担心我熬夜到很晚了。

好了,问题来了,我们知道lambda表达式分为 语句lambda和表达式lambda  ,那么二者有何区别呢?从字面上理解语句lambda是不是就是用大括号括起来的呢?ok,给出代码来理解吧。

(string str) => { return str.length; }  /*语句lambda(有大括号和return)*/(string str) => str.length  /*表达式lambda(没有大括号和return,只有一个式子)*/

那问题又来了,lambda表达式到底是什么呢?我们依然用反编译来查看  list.ForEach(d => Console.WriteLine(d.Age)); 对应的C#代码如下:

看ForEach()方法里面的参数意思大概是匿名方法委托,接着我们点击进去看看,代码如下:

我们接着点击Action看看,如下:

一下就豁然开朗了,这不正说明 lambda表达式的实质就是匿名方法 吗!所以现在想想,lambda表达式的本质是匿名方法,匿名方法的本质是通过委托实现的。应该就是这样了。

lambda表达式进化过程

我们就一个扩展方法的实例来演示lambda表达式演变的过程是多么的惟妙惟肖。

假设如下场景:在花千骨电视中找出白子画出来,找对了你就赢了!我们获得给出一个花千骨众角色列表,再选出白子画即可。

             /*根据条件找出所需,返回true你就赢了,反之则输*/static bool SelDefine_Extension_IEnumerable<T>(this IEnumerable<T> source, Func<T, bool> func){                 foreach (var item in source){                    if (func(item)){                        return true;}}                 return false;}

下面给出集合列表:

            var list = new List<string>() { "花千骨", "白子画", "东方彧卿", "霓漫天", "糖宝", "落十一", "轻水", "孟玄朗" };

然后在控制台执行扩展方法进行查询,在此列出 lambda表达式6部曲 :

            list.SelDefine_Extension_IEnumerable(

从开始的繁琐,复杂到最终的简洁,每一个过程微软大大也是作出一定的努力,先点给赞先!就上述用一副图来看,估计会更加清晰明了吧

lambda表达式演变六部曲

转载于:https://blog.51cto.com/hzz333/1918812

lambda表达式之进化相关推荐

  1. 委托到Lambda的进化: ()= {} 这个lambda表达式就是一个无参数的委托及具体方法的组合体。...

    1.原始的委托 (.net 1.0) using System; using System.Collections.Generic; using System.ComponentModel; usin ...

  2. C#复习笔记(4)--C#3:革新写代码的方式(Lambda表达式和表达式树)

    Lambda表达式和表达式树 先放一张委托转换的进化图 看一看到lambda简化了委托的使用. lambda可以隐式的转换成委托或者表达式树.转换成委托的话如下面的代码: Func<string ...

  3. Lambda 表达式基础理论与示例

    Lambda 表达式基础理论与示例 Lambda 表达式,也可称为闭包,推动 Java 8 发布的最重要新特性. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). 使用 Lam ...

  4. lambda表达式树

    一.定义: 表达式树又称为表达式目录树,以数据形式表示语言级代码.所有的数据都存储在树结构中,每个结点表示一个表达式(Expression). 二.要点: –Lambda表达式的参数类型可以忽略,因为 ...

  5. java 8 lambda reduce_JDK8新特性Lambda表达式体验

    "Lambda 表达式"(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstra ...

  6. java saf_Java 8 Lambda表达式探险

    为什么? 我们为什么需要Lambda表达式 主要有三个原因: > 更加紧凑的代码 比如Java中现有的匿名内部类以及监听器(listeners)和事件处理器(handlers)都显得很冗长 &g ...

  7. lamda表达式python_Python--13 lambda表达式

    python 允许使用lambda表达式来创建匿名函数 lambda表达式 >>>def ds(x): ... return 2 * x +1 ... >>> ds ...

  8. C++11:Lambda表达式(匿名函数)理解

    C++在C11标准中引入了匿名函数,即没有名字的临时函数,又称之为lambda表达式.lambda表达式 实质上是创建一个匿名函数/对象.即你可以理解为(Lambda 表达式实际上是一个函数,只是它没 ...

  9. java8 lambda 表达式详解

    lambada 表达式实质上是一个匿名方法,但该方法并非独立执行,而是用于实现由函数式接口定义的唯一抽象方法 使用 lambda 表达式时,会创建实现了函数式接口的一个匿名类实例 可以将 lambda ...

最新文章

  1. Linux进阶 vim grep sed awk 正则表达式
  2. c语言倒计时不影响进程_2017级C语言大作业 - 见缝插针
  3. windows批量创建用户
  4. SAP如何直接往系统中数据库表插入数据
  5. 【转载】分布式事务 介绍
  6. c语言保存文件格式如何改回来,急求如何将下列C语言程序数据存储到文件中?...
  7. ❤️六W字《计算机基础知识》(五)(建议收藏)❤️
  8. 浅谈分布式一致性协议之3PC
  9. ios nstimer实现延时_iOS 中常见 Crash 总结
  10. 数据结构基础温故-5.图(上):图的基本概念
  11. 【数学】线性代数技巧篇
  12. python敏感词替换
  13. Delphi FireMonkey 的动画以及多线程
  14. matlab pi调节器,pi调节器的输入和输出_pi调节器的传递函数
  15. chrome浏览器视频加速插件安装教程
  16. JAVA我的世界怎么做成就_我的世界:又一人解锁100%成就!这几项公认最难任务,你能完成吗...
  17. 图像在空域上的平滑处理
  18. GTS、GCK,GSR全称
  19. roboware安装包
  20. 新玺配资:股票市场中的配股是什么意思

热门文章

  1. c++读出像素矩阵_Python传numpy矩阵调c++(求3D图像连通区域)
  2. matlab 分隔线,matlab字符分割方法
  3. dockers log查询dockers的文件_Tomcat PUT方法任意文件上传
  4. java jndi tcp_spring配置下通过tomcat的jndi服务连接数据库
  5. linux内核开文件系统,内核必须懂(二): Linux文件系统初探
  6. bootstrap-table toolbar图标换文字_iPhone 也能随意换字体啦~
  7. SSM 整合 4:Spring IoC 容器基于的两个重要接口 BeanFactory 和 ApplicationContext
  8. c++ dicom图像切割_【高训智造】原创专业课堂第225期--定位滑座的线切割加工
  9. 如何设置mysql表中文乱码_php mysql表中文乱码问题如何解决
  10. echart vue 图表大小_cesium+vue,性能优化