前言

在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 = , Gender = false},
new Person(){ Name = "白子画 (长留尊上)", Age = , Gender = true},
new Person(){ Name = "东方彧卿 (异朽阁主及蜀国大学士)", Age = , Gender = true},
new Person(){ Name = "轻水 (长留弟子)", Age = , Gender = false},
new Person(){ Name = "孟玄朗 (蜀国皇帝及长留弟子)", Age = , 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 > ; });

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

Func

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

list.Select(d => new { Name = d.Name}); /*lambda表达式中的匿名类*/

好了,一切都变得如此明朗。自从有了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(new Func<string, bool>(delegate(string item) { return item.Equals("白子画"); }));

            list.SelDefine_Extension_IEnumerable(delegate(string item) { return item.Equals("白子画"); });

            list.SelDefine_Extension_IEnumerable((string item) => { return item.Equals("白子画"); });

            list.SelDefine_Extension_IEnumerable((string item) => item.Equals("白子画"));

            list.SelDefine_Extension_IEnumerable((item) => item.Equals("白子画"));

            list.SelDefine_Extension_IEnumerable(item => item.Equals("白子画"));

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

lambda表达式演变六部曲

lambda表达式之进化的更多相关文章

  1. Java中Lambda表达式的进化之路

    Lambda表达式的进化之路 为什么要使用Lambda表达式 可以简洁代码,提高代码的可读性 可以避免匿名内部类定义过多导致逻辑紊乱 在原先实现接口抽象方法的时候,需要通过定义一个实现接口的外部类来实 ...

  2. C#中的Lambda表达式和表达式树

    在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...

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

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

  4. 函数进化到Lambda表达式的三过程

    假如我们想要从一个整型数组中取出其中是奇数的选项,其实现方式有很多, 接下来通过三种方法的对比理解Lambda表达式的用途,需要了解的朋友可以参考下         //声明委托类型 public d ...

  5. 动态生成C# Lambda表达式

    转载:http://www.educity.cn/develop/1407905.html,并整理! 对于C# Lambda的理解我们在之前的文章中已经讲述过了,那么作为Delegate的进化使用,为 ...

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

    原文:匿名方法,Lambda表达式,高阶函数 匿名方法 c#2.0引入匿名方法,不必创建单独的方法,因此减少了所需的编码系统开销. 常用于将委托和匿名方法关联,例如1. 使用委托和方法关联: this ...

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

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

  8. 委托学习总结(二)匿名方法和lambda表达式

    之前总结了委托这个困惑着大多初学者的概念,继续来学习匿名方法和lambda表达式 (1)我们之前写了这样一段代码 //自定义一个委托 public delegate int Expression(in ...

  9. 你知道C#中的Lambda表达式的演化过程吗?

    那得从很久很久以前说起了,记得那个时候... 懵懂的记得从前有个叫委托的东西是那么的高深难懂. 委托的使用 例一: 什么是委托? 个人理解:用来传递方法的类型.(用来传递数字的类型有int.float ...

随机推荐

  1. 51nod算法马拉松15

    智力彻底没有了...看来再也拿不到奖金了QAQ... A B君的游戏 因为数据是9B1L,所以我们可以hash试一下数据... #include<cstdio> #include<c ...

  2. BZOJ4597: [Shoi2016]随机序列

    Description 你的面前有N个数排成一行.分别为A1, A2, … , An.你打算在每相邻的两个 Ai和 Ai+1 间都插入一个加号或者 减号或者乘号.那么一共有 3^(n-1) 种可能的表 ...

  3. 来自XP的道别信

    当你们看到这封信的时候,很抱歉要和大家说再见了! 亲爱的你们,对不起,请不要为我哭泣,请让我们一起度过这最后的时光. 请记住那个在蓝天白云下奔跑的我!

  4. Angular初步

    一.angular.js是什么? angular.js是一个javascript的框架,与jquery是一个级别的,区别是jquery主要是擅长dom操作,而angular主要是擅长绑定数据显示数据. ...

  5. github for windows 安装 使用

    遇到无数的未知问题.光是安装就搞了好久. 安装程序显示安装了.NET Framework4.5,然后提示重启.重启后,自动开始下载文件,最多到2%就走不动了. 后来请求了下面这个链接,才开始下载了(虽 ...

  6. Markdown Blog Testing

    # 测试一下markdown写法 貌似之前的文章不能再重新套用markdown语法了? 1 2 3

  7. homework-01

    我的GitHub账户名是Firedamp. 其实我最一开始看到最大子序列的和这个题目,最先想到的就是最简单的O(n^3)的算法,在课堂上教的也确实是这个程序,但是这种算法的时间复杂度必然是最高的,在数 ...

  8. webpack的配置

    使用webpack工具需要配置一个根目录下的配置文件,文件名默认为webpack.condfig.js,配置文件导出一个模块对象,包含了webpack工具的相关配置参数,这个模块对象将会以参数形式被引 ...

  9. Android之Json的学习

    json数据包含json对象,json数组,对象是{ },数组是[ ], 数组里面还可以包含json对象,json对象之间是用逗号(,)隔开 形式如下: { "languages" ...

  10. JQM (功能栏、导航条)

    在Mobile中导航条的基本结构: <div data-role="navbar"> ul>li>a </div> 其中含有“行(grid)”和 ...