【Linq】Lamda演变历史
一..NetFramework 1.0 1.1时代
以前学习委托,大部分流程都是在这里声明委托,实例化的时候不得不声明一个方法,在写一个方法不得不传进入,这个方法与声明的委托参数返回值吻合,然后把这个方法传递进去。
namespace LamdaHistory { public static class NetFramework1 { public delegate void NoReturnNoPara();//声明委托 public delegate void NoReturnWithPara(int x, string y);//声明委托 public static void Show() { NoReturnNoPara method = new NoReturnNoPara(DoNothing); method.Invoke(); NoReturnWithPara method2 = new NoReturnWithPara(Study); method2.Invoke(123, "董小姐"); } private static void DoNothing() { Console.WriteLine("This is DoNothing"); } private static void Study(int id, string name) { Console.WriteLine($"{id} {name} 学习.Net高级班"); } } }
如下图所示委托编译后从IL层面看就是一个密封的,且其继承自MulticastDelegete的类
二.NetFramework 2.0
2.1.不在像以前老老实实写方法名称,而是把方法体直接写在实例化委托这里了,前面加关键字delegate,匿名方法没有名字
2.2.可以访问局部变量age,如果像1.0时代,是个方法的话,没有办法访问到局部变量age
namespace LamdaHistory { public static class NetFramework2 { public delegate void NoReturnNoPara();//声明委托 public delegate void NoReturnWithPara(int x, string y);//声明委托 public static void Show() { int age = 20; NoReturnNoPara method = new NoReturnNoPara(delegate { Console.WriteLine("This is DoNothing"); }); method.Invoke(); NoReturnWithPara method2 = new NoReturnWithPara(delegate(int id,string name) { Console.WriteLine($"{id} {name} {age} 学习.Net高级班"); }); method2.Invoke(123, "董小姐"); } } }
三..NetFramework3.0
3.1.把delegate关键字去掉,增加了一个箭头,箭头念goes to,这就是Lamda表达式参数列表=>方法体
amespace LamdaHistory { public static class NetFramework3 { public delegate void NoReturnNoPara();//声明委托 public delegate void NoReturnWithPara(int x, string y);//声明委托 public static void Show() { int age = 20; NoReturnNoPara method = new NoReturnNoPara(()=> { Console.WriteLine("This is DoNothing"); }); method.Invoke(); NoReturnWithPara method2 = new NoReturnWithPara((int id,string name) => { Console.WriteLine($"{id} {name} {age} 学习.Net高级班"); }); method2.Invoke(123, "董小姐"); //省略参数类型int和string,编译器的语法糖,虽然没写,编译时还是有的, //根据委托推算的,因为NoReturnWithPara这个委托就是就是接收一个int和string NoReturnWithPara method3 = new NoReturnWithPara((id, name) => { Console.WriteLine($"{id} {name} {age} 学习.Net高级班"); }); method3.Invoke(456, "张小姐"); //如果方法体只有一行,可以去掉大括号和分号 NoReturnWithPara method4 = new NoReturnWithPara((id, name) => Console.WriteLine($"{id} {name} {age} 学习.Net高级班") ); method4.Invoke(789, "王小姐"); //new NoReturnWithPara委托可以省掉,也是语法糖,编译器自动加上 NoReturnWithPara method5 = (id, name) => Console.WriteLine($"{id} {name} {age} 学习.Net高级班"); method5.Invoke(101, "杨小姐"); } } }
3.2.省略参数类型int和string,编译器的语法糖,虽然没写,编译时还是有的,根据委托推算的,因为NoReturnWithPara这个委托就是就是接收一个int和string
NoReturnWithPara method3 = new NoReturnWithPara((id, name) => { Console.WriteLine($"{id} {name} {age} 学习.Net高级班"); }); method3.Invoke(456, "张小姐");
3.3.如果方法体只有一行,可以去掉大括号和分号
//如果方法体只有一行,可以去掉大括号和分号 NoReturnWithPara method4 = new NoReturnWithPara((id, name) => Console.WriteLine($"{id} {name} {age} 学习.Net高级班") ); method4.Invoke(789, "王小姐");
3.4.new NoReturnWithPara委托也可以省掉,也是语法糖,编译器自动加上
//new NoReturnWithPara委托可以省掉,也是语法糖,编译器自动加上 NoReturnWithPara method5 = (id, name) => Console.WriteLine($"{id} {name} {age} 学习.Net高级班"); method5.Invoke(101, "杨小姐");
四.Lamda表达式是什么?
4.1.lamda不是一个委托,因为编译器语法糖省略了new NoReturnWithPara,所以只是看起来像是1个委托,但是实际上从上面可以看出lamda只是实例化委托的一个参数,lamda就是个匿名方法。
4.2.从IL层分析,lamda是匿名方法,但是编译的时候会分配一个名字,还会产生一个私有sealed类,这里增加一个方法,这个方法就是跟lambda表达式一一对应的。
五.Lamda在多播委托中的特点-无法移除
lamda表达式在多播委托为什么加1次,减1次,为什么减不掉呢?多播委托里面的lamda无法移除,虽说两个lamda的方法内容一样,lamda是匿名方法,但是编译器编译后会自动给分配方法名字,其实是2个不同的方法,所以无法移除,而Study是同1个方法,所以可以移除。
namespace LamdaHistory { public class MulticastDelegate { public delegate void NoReturnWithPara(int x, string y);//声明委托 public void Show() { NoReturnWithPara method = new NoReturnWithPara(this.Study); method += this.Study; method += (id, name) => { Console.WriteLine($"{id} {name} 学习.Net Core"); }; method -= this.Study; method -= (id, name) => { Console.WriteLine($"{id} {name} 学习.Net Core"); }; method.Invoke(123, "张三"); } private void Study(int id, string name) { Console.WriteLine($"{id} {name} 学习.Net Framework"); } } }