Lambda表达式的诞生过程
这是一篇很经典的文章,解决了工作中一些使用过但是又不太明白的知识点,今天终于弄明白了。花了一晚上重新整的,坚决要分享出来!!!
那得从很久很久以前说起了,记得那个时候...
懵懂的记得从前有个叫委托的东西是那么的高深难懂。
委托的使用
例一:
public delegate void AddDelegate(); public class Program { public Program() { AddDelegate add = new AddDelegate(Add); } public void Add() { Console.Write("hello"); } }
什么是委托?
个人理解:用来传递方法的类型。(用来传递数字的类型有int、float、double,用来传递方法的就有委托)
例二:
1 public delegate void Callback(); 2 class Program 3 { 4 public Program() 5 { 6 SendMail(SavaLogOK, SaveLogErr); 7 } 8 public void SendMail(Callback sentResult, Callback errorAction) 9 { 10 //...发送邮件... 11 if (true) 12 sentResult(); //发送成功 13 else 14 errorAction(); //发送失败 15 } 16 17 public void SaveLogErr() 18 { } 19 public void SavaLogOK() 20 { } 21 }
又经过了很久很久...
匿名方法
很多时候委托接收的方法是一次性的或者方法体是非常简单的...
例三:
1 public delegate int AddDelegate(int a, int b); 2 public class Program 3 { 4 public Program() 5 { 6 AddDelegate addTest = new AddDelegate(Add); 7 addTest(1,2);//执行方法 8 } 9 public int Add(int a, int b) 10 { 11 return a + b; 12 } 13 }
我们可以写成:
1 public delegate int AddDelegate(int a, int b); 2 public class Program 3 { 4 public Program() 5 { 6 AddDelegate addTest = new AddDelegate(delegate(int a, int b) { return a + b; }); 7 } 8 9 }
有没有发现我们每次都要定义委托,很多时候签名可能是一样的。这样就没有必要定义重复的。
然后又过了很久很久...
Func和Action
可能老大也觉得我们每次定义委托有点傻,所以干脆在框架内一次定义好所有可能用到的委托。那千变万化的方法签名怎么可能定义得全?没关系,定义成泛型的不就可以了吗。
先说Func:
1 public delegate int AddDelegate(int a, int b);//这种委托不用在定义 2 public class Program 3 { 4 public Program() 5 { 6 // AddDelegate addTest = new AddDelegate(delegate(int a, int b) { return a + b; }); 7 Func<int, int, int> addTest = new Func<int, int, int>(delegate(int a, int b) { return a + b; }); 8 } 9 10 }
细心的朋友可能看到了,Func相对于AddDelegate多定义了一个int。多出了的那个是指的是返回类型。我们F12看对应的定义:
1 // 摘要: 2 // 封装一个具有两个参数并返回 TResult 参数指定的类型值的方法。 3 // 4 // 参数: 5 // arg1: 6 // 此委托封装的方法的第一个参数。 7 // 8 // arg2: 9 // 此委托封装的方法的第二个参数。 10 // 11 // 类型参数: 12 // T1: 13 // 此委托封装的方法的第一个参数类型。 14 // 15 // T2: 16 // 此委托封装的方法的第二个参数类型。 17 // 18 // TResult: 19 // 此委托封装的方法的返回值类型。 20 // 21 // 返回结果: 22 // 此委托封装的方法的返回值。 23 [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] 24 public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
关于上面Func的写法我们可以简写成:(语法糖而已,编译后还是注释的代码)
1 // AddDelegate addTest = new AddDelegate(delegate(int a, int b) { return a + b; }); 2 // Func<int, int, int> addTest = new Func<int, int, int>(delegate(int a, int b) { return a + b; }); 3 Func<int, int, int> addTest = delegate(int a, int b) { return a + b; };
再看Action:
1 class Program 2 { 3 public Program() 4 { 5 SendMail(SavaLogOK, SaveLogErr); 6 } 7 public void SendMail(Action sentResult, Action errorAction) 8 { 9 //...发送邮件... 10 if (true) 11 sentResult(); //发送成功 12 else 13 errorAction(); //发送失败 14 } 15 16 public void SaveLogErr() 17 { } 18 public void SavaLogOK() 19 { } 20 }
提醒:以后如果我们写代码的时候如果写到到delegate...,你要马上想到是否可以用Func或者Action来代替呢?C#4中的Action和Func有16个参数,足够你用了。
我们等了又等,又过了好久好久...
Lambda的诞生
1 public Program() 2 { 3 Func<int, int, int> addTest = delegate(int a, int b) { return a + b; }; 4 Func<int, int, int> addTest2 = (int a, int b) => { return a + b; }; 5 }
我XX,这TM就是亲兄弟啊。直接去掉delegate关键字,然后加一个=>就成了lambda表达式了。(=>读作goes to)
我们继续简化:
1 public Program() 2 { 3 Func<int, int, int> addTest = (int a, int b) => { return a + b; }; 4 Func<int, int, int> addTest2 = (a, b) => { return a + b; }; 5 }
丢掉参数类型也是可以的,因为强大的VS可以根据泛型委托Func自己推断出来参数类型。
还可以简化吗?当然:
1 Func<int, int, int> addTest = (int a, int b) => { return a + b; }; 2 Func<int, int, int> addTest2 = (a, b) => { return a + b; }; 3 Func<int, int, int> addTest3 = (a, b) => a + b;
return关键字也不要了,大括号也不要了。(当然,方法体只有单条语句才能怎么做)
现在看起来已经非常接*我们*时用的Lambda表达式了。
如果传入参数只有一个的话,我们还可以继续简化:
1 Func<int, int> func = (a) => 2 * a;
func = a => 2 * a;
这就是我们*时见得最多的lambda长相了。
要长成这样也是有要求的:
- 只能有一个传入参数
- 方法体只能只一条语句。
关于第1点,lambda我们*时用得较多的是基于IEnumerable或IQueryable,所以只能有一个参数也就满足了。
关于第2点,我们使用扩展方法的链式编程来解决。
如:(用链式来解决第二点)
1 public Program() 2 { 3 Func<IEnumerable<string>, IEnumerable<string>> fun = t => 4 t.Where(v => v.Length > 10).Reverse().OrderBy(v => v.Length).ToList(); 5 }
从此,我们过上了幸福的生活...
借《深入理解C#》中的一图:
小知识:(异步Lambda)
1 Func<Student, Task<bool>> func = async t => 2 { 3 await Task.Delay(100);//等待100毫秒 4 return false; 5 };
结束:
本文简短的说了下lambda表达式在C#中的一步步演化。说的不一定对,轻拍!
FROM :http://www.cnblogs.com/zhaopei/p/5769782.html