Lambda表达式的本质是匿名函数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lambda表达式的本质是匿名函数相关的知识,希望对你有一定的参考价值。
1.委托的简介:
委托可以简单的理解为方法的列表,添加的方法的参数类型,个数,顺序必须和委托一致,
也就是说委托起到了托管方法的作用,并且约束了要调用的方法.
1 //1声明委托 2 public delegate void NoReturnNoPara(); 3 public delegate void NoReturnWithPara(string name, int id); 4 public delegate int WithReturnNoPara(); 5 public delegate string WithReturnWithPara(string name);
基础代码:
1 private void ShowPerson(string name, int id) 2 { 3 Console.WriteLine("this is id={0} name={1}", id, name); 4 }
1 public class Student 2 { 3 public int Id { get; set; } 4 public int ClassId { get; set; } 5 public string Name { get; set; } 6 public int Age { get; set; } 7 8 public void Study() 9 { 10 Console.WriteLine("正在学习高级班"); 11 } 12 } 13 14 /// <summary> 15 /// 班级 16 /// </summary> 17 public class Class 18 { 19 public int Id { get; set; } 20 public string Name { get; set; } 21 }
1 { 2 Student student = new Student() 3 { 4 Id = 1, 5 ClassId = 11, 6 Name = "Courage-dhj" 7 }; 8 student.Study(); 9 10 var people = new //匿名类 11 { 12 Id = 1, 13 ClassId = 11, 14 Name = "Courage-dhj" 15 }; 16 Console.WriteLine("{0} {1} {2}", people.Id, people.Name, people.ClassId); 17 }
1 { 2 NoReturnWithPara method = new NoReturnWithPara(ShowPerson);//2 实例化委托 3 method.Invoke("盗墓者", 468);//3 委托调用 4 ShowPerson("盗墓者", 468);//方法的普通调用 5 }
2.匿名方法: 用delegate代替了方法名而已(修饰符和返回类型这里看作方法名)
1 { 2 NoReturnWithPara method = new NoReturnWithPara( 3 delegate(string name, int id) 4 { 5 Console.WriteLine("this is id={0} name={1}", id, name); 6 });//匿名方法 7 method.Invoke("盗墓者", 468); 8 }
3.Lambda表达式
1 { 2 NoReturnWithPara method = new NoReturnWithPara( 3 (string name, int id) => 4 { 5 Console.WriteLine("this is id={0} name={1}", id, name); 6 });//lambda表达式 把delegate换成箭头 7 method.Invoke("盗墓者", 468); 8 //lambda表达式的本质就是一个匿名方法,,也就是一个方法 9 }
因为委托对方法有约束作用,所以,方法的参数类型可以省略
1 { 2 NoReturnWithPara method = new NoReturnWithPara( 3 (name, id) =>//lambda表达式方法主体只有一行,可以去掉大括号和分号 4 Console.WriteLine("this is id={0} name={1}", id, name) 5 ); 6 method.Invoke("盗墓者", 468); 7 }
其他的形式:
1 { 2 NoReturnWithPara method = new NoReturnWithPara( 3 (name, id) =>//lambda表达式方法主体只有一行,可以去掉大括号和分号 4 Console.WriteLine("this is id={0} name={1}", id, name) 5 ); 6 method.Invoke("盗墓者", 468); 7 }
{ //new一个委托的时候,可以简写 NoReturnWithPara method = (name, id) => Console.WriteLine("this is id={0} name={1}", id, name);//常用的形式 method.Invoke("盗墓者", 468); }
4. Action 和 Func----这是系统自带的委托,方便我们使用.
4.1-Action-无返回值的委托---看下面的in也看的出来啦!
先查看系统代码的说明:
1 namespace System 2 { 3 // 摘要: 4 // 封装一个方法,该方法不具有参数并且不返回值。 5 [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] 6 public delegate void Action(); 7 }
1 namespace System 2 { 3 // 摘要: 4 // 封装一个方法,该方法只有一个参数并且不返回值。 5 // 6 // 参数: 7 // obj: 8 // 此委托封装的方法的参数。 9 // 10 // 类型参数: 11 // T: 12 // 此委托封装的方法的参数类型。 13 public delegate void Action<in T>(T obj); 14 }
1 1 namespace System 2 2 { 3 3 // 摘要: 4 4 // 封装一个方法,该方法具有 16 个参数并且不返回值。 5 5 // 6 6 // 参数: 7 7 // arg1: 8 8 // 此委托封装的方法的第一个参数。 9 9 // 10 10 // arg2: 11 11 // 此委托封装的方法的第二个参数。 12 12 // 13 13 // arg3: 14 14 // 此委托封装的方法的第三个参数。 15 15 // 16 16 // arg4: 17 17 // 此委托封装的方法的第四个参数。 18 18 // 19 19 // arg5: 20 20 // 此委托封装的方法的第五个参数。 21 21 // 22 22 // arg6: 23 23 // 此委托封装的方法的第六个参数。 24 24 // 25 25 // arg7: 26 26 // 此委托封装的方法的第七个参数。 27 27 // 28 28 // arg8: 29 29 // 此委托封装的方法的第八个参数。 30 30 // 31 31 // arg9: 32 32 // 此委托封装的方法的第九个参数。 33 33 // 34 34 // arg10: 35 35 // 此委托封装的方法的第十个参数。 36 36 // 37 37 // arg11: 38 38 // 此委托封装的方法的第十一个参数。 39 39 // 40 40 // arg12: 41 41 // 此委托封装的方法的第十二个参数。 42 42 // 43 43 // arg13: 44 44 // 此委托封装的方法的第十三个参数。 45 45 // 46 46 // arg14: 47 47 // 此委托封装的方法的第十四个参数。 48 48 // 49 49 // arg15: 50 50 // 此委托封装的方法的第十五个参数。 51 51 // 52 52 // arg16: 53 53 // 此委托封装的方法的第十六个参数。 54 54 // 55 55 // 类型参数: 56 56 // T1: 57 57 // 此委托封装的方法的第一个参数类型。 58 58 // 59 59 // T2: 60 60 // 此委托封装的方法的第二个参数类型。 61 61 // 62 62 // T3: 63 63 // 此委托封装的方法的第三个参数类型。 64 64 // 65 65 // T4: 66 66 // 此委托封装的方法的第四个参数类型。 67 67 // 68 68 // T5: 69 69 // 此委托封装的方法的第五个参数的类型。 70 70 // 71 71 // T6: 72 72 // 此委托封装的方法的第六个参数的类型。 73 73 // 74 74 // T7: 75 75 // 此委托封装的方法的第七个参数的类型。 76 76 // 77 77 // T8: 78 78 // 此委托封装的方法的第八个参数的类型。 79 79 // 80 80 // T9: 81 81 // 此委托封装的方法的第九个参数的类型。 82 82 // 83 83 // T10: 84 84 // 此委托封装的方法的第十个参数的类型。 85 85 // 86 86 // T11: 87 87 // 此委托封装的方法的第十一个参数的类型。 88 88 // 89 89 // T12: 90 90 // 此委托封装的方法的第十二个参数的类型。 91 91 // 92 92 // T13: 93 93 // 此委托封装的方法的第十三个参数的类型。 94 94 // 95 95 // T14: 96 96 // 此委托封装的方法的第十四个参数的类型。 97 97 // 98 98 // T15: 99 99 // 此委托封装的方法的第十五个参数的类型。 100 100 // 101 101 // T16: 102 102 // 此委托封装的方法的第十六个参数的类型。 103 103 public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); 104 104 }
实例化:
1 //接受0到16个参数的 无返回值 泛型委托 2 Action act1 = () => Console.WriteLine("123"); //1 3 Action<string> act2 = t => { };//2 4 Action<Student, Class, int, long, Student, Class, int, long, Student, Class, int, long, Student, Class, int, long> act3 = null;//3
4.2. Func---有返回值---看out就看得出来啦!
1 namespace System 2 { 3 // 摘要: 4 // 封装一个不具有参数但却返回 TResult 参数指定的类型值的方法。 5 // 6 // 类型参数: 7 // TResult: 8 // 此委托封装的方法的返回值类型。 9 // 10 // 返回结果: 11 // 此委托封装的方法的返回值。 12 [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] 13 public delegate TResult Func<out TResult>(); 14 }
1 namespace System 2 { 3 // 摘要: 4 // 封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。 5 // 6 // 参数: 7 // arg: 8 // 此委托封装的方法的参数。 9 // 10 // 类型参数: 11 // T: 12 // 此委托封装的方法的参数类型。 13 // 14 // TResult: 15 // 此委托封装的方法的返回值类型。 16 // 17 // 返回结果: 18 // 此委托封装的方法的返回值。 19 [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] 20 public delegate TResult Func<in T, out TResult>(T arg); 21 }
1 namespace System 2 { 3 // 摘要: 4 // 封装一个方法,该方法具有 16 个参数,并返回 TResult 参数所指定的类型的值。 5 // 6 // 参数: 7 // arg1: 8 // 此委托封装的方法的第一个参数。 9 // 10 // arg2: 11 // 此委托封装的方法的第二个参数。 12 // 13 // arg3: 14 // 此委托封装的方法的第三个参数。 15 // 16 // arg4: 17 // 此委托封装的方法的第四个参数。 18 // 19 // arg5: 20 // 此委托封装的方法的第五个参数。 21 // 22 // arg6: 23 // 此委托封装的方法的第六个参数。 24 // 25 // arg7: 26 // 此委托封装的方法的第七个参数。 27 // 28 // arg8: 29 // 此委托封装的方法的第八个参数。 30 // 31 // arg9: 32 // 此委托封装的方法的第九个参数。 33 // 34 // arg10: 35 // 此委托封装的方法的第十个参数。 36 // 37 // arg11: 38 // 此委托封装的方法的第十一个参数。 39 // 40 // arg12: 41 // 此委托封装的方法的第十二个参数。 42 // 43 // arg13: 44 // 此委托封装的方法的第十三个参数。 45 // 46 // arg14: 47 // 此委托封装的方法的第十四个参数。 48 // 49 // arg15: 50 // 此委托封装的方法的第十五个参数。 51 // 52 // arg16: 53 // 此委托封装的方法的第十六个参数。 54 // 55 // 类型参数: 56 // T1: 57 // 此委托封装的方法的第一个参数类型。 58 // 59 // T2: 60 // 此委托封装的方法的第二个参数类型。 61 // 62 // T3: 63 // 此委托封装的方法的第三个参数类型。 64 // 65 // T4: 66 // 此委托封装的方法的第四个参数类型。 67 // 68 // T5: 69 // 此委托封装的方法的第五个参数的类型。 70 // 71 // T6: 72 // 此委托封装的方法的第六个参数的类型。 73 // 74 // T7: 75 // 此委托封装的方法的第七个参数的类型。 76 // 77 // T8: 78 // 此委托封装的方法的第八个参数的类型。 79 // 80 // T9: 81 // 此委托封装的方法的第九个参数的类型。 82 // 83 // T10: 84 // 此委托封装的方法的第十个参数的类型。 85 // 86 // T11: 87 // 此委托封装的方法的第十一个参数的类型。 88 // 89 // T12: 90 // 此委托封装的方法的第十二个参数的类型。 91 // 92 // T13: 93 // 此委托封装的方法的第十三个参数的类型。 94 // 95 // T14: 96 // 此委托封装的方法的第十四个参数的类型。 97 // 98 // T15: 99 // 此委托封装的方法的第十五个参数的类型。 100 // 101 // T16: 102 // 此委托封装的方法的第十六个参数的类型。 103 // 104 // TResult: 105 // 此委托封装的方法的返回值类型。 106 // 107 // 返回结果: 108 // 此委托封装的方法的返回值。 109 public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); 110 }
不过,不管怎么变,Func的最后一个始终都时out,因为它时有返回值的呗!
1 //注意:这是一个新的类型,类型的不同包括了参数的个数的哦. 2 public delegate TResult ; 3 Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, in T17, out TResult> 4 (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, 5 T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17);
1 //接受0到16个参数的 带返回值 泛型委托 2 Func<int> func1 = () => DateTime.Now.Millisecond;//4--返回int类型
//下面都返回string类型 3 Func<int,
string> func2 = t => DateTime.Now.Millisecond.ToString();//5 4 Func<Student, Class, int, long, Student, Class, int, long, Student, Class, int, long, Student, Class, int, long,
string> func3 = null;//6 5 //调用自己写的,17个参数 6 Func<Student, Student, Class, int, long, Student, Class, int, long, Student, Class, int, long, Student, Class, int, long,
string> func4 = null;//6
5 扩展方法: 静态类的静态方法第一个参数加上 this.(静态类不一定要加上static,只要有静态方法的类就是静态类)
1 /// <summary> 2 /// 静态类的静态方法,第一个参数前面加上this 3 /// </summary> 4 public static class ExtendTest 5 { 6 /// <summary> 7 /// 转成int 失败给0写日志 8 /// </summary> 9 /// <param name="sNumber"></param> 10 /// <returns></returns> 11 public static int ToInt(this string sNumber) 12 { 13 int iNumber = 0; 14 if (int.TryParse(sNumber, out iNumber)) 15 { 16 return iNumber; 17 } 18 else 19 { 20 Console.WriteLine("{0} 转换失败,给出默认值", sNumber); 21 return 0; 22 } 23 } 24 25 public static void Study(this Student student) 26 { 27 Console.WriteLine("1234"); 28 } 29 30 public static void StudyVip(this Student student) 31 { 32 Console.WriteLine("1234"); 33 } 34 35 public static void ConsoleShow(this object oValue) 36 { 37 Console.WriteLine(oValue); 38 } 39 40 }
调用: 就像给某个类添加了一个方法一样,所以才叫扩展方法啊!
1 string sNumber = "123345"; 2 ExtendTest.ToInt(sNumber);//普通调用--返回一个int 3 sNumber.ToInt();//扩展方法调用--返回一个int 4 5 Student student = new Student() 6 { 7 Name = "天道无情(387-天道无情-男)" 8 }; 9 student.StudyVip(); 10 student.Study(); 11 student.ConsoleShow();
不过,扩展方法并非给this 修饰的类添加了一个方法,而是通过this添加了一个纽带.
当我们调用扩展方法时,还是进入了我们自己写的方法里.
只不过它看起来像时我们给一个类注入了一个方法而已.(这里用注入很形象的形容)
记住:扩展方法时写在一个外部的静态类里,并且是一个静态方法,参数类型前加this.
6. Linq 查询
1 private static List<Student> GetStudentList() 2 { 3 #region 初始化数据 4 List<Student> studentList = new List<Student>() 5 { 6 new Student() 7 { 8 Id=1, 9 Name="Answer(学委-answer-男)", 10 Age=25, 11 ClassId=2 12 }, 13 new Student() 14 { 15 Id=2, 16 Name=" LTS_信仰I(196-LTS_信仰I-男-深圳)", 17 Age=36, 18 ClassId=1 19 }, 20 new Student() 21 { 22 Id=3, 23 Name="ObjectIsNotFound", 24 Age=24, 25 ClassId=2 26 }, 27 new Student() 28 { 29 Id=4, 30 Name="落单的候鸟", 31 Age=25, 32 ClassId=2 33 }, 34 new Student() 35 { 36 Id=1, 37 Name="夜的乐章", 38 Age=31, 39 ClassId=2 40 }, 41 new Student() 42 { 43 Id=1, 44 Name="知心dě朋友=(357-杰仔-男-广州)", 45 Age=18, 46 ClassId=2 47 }, 48 new Student() 49 { 50 Id=1, 51 Name="我", 52 Age=33, 53 ClassId=2 54 }, 55 new Student() 56 { 57 Id=1, 58 Name="小逸", 59 Age=28, 60 ClassId=2 61 }, 62 new Student() 63 { 64 Id=1, 65 Name="季雨林", 66 Age=27, 67 ClassId=2 68 }, 69 new Student() 70 { 71 Id=1, 72 Name="dean", 73 Age=34, 74 ClassId=2 75 }, 76 new Student() 77 { 78 Id=1, 79 Name="yup_h", 80 Age=21, 81 ClassId=1 82 } 83 }; 84 #endregion 初始化数据 85 return studentList; 86 }
普通程序员一般会想的方法:
1 List<Student> studentList = GetStudentList(); 2 { 3 List<Student> targetList = new List<Student>(); 4 foreach (var item in studentList) 5 { 6 if (item.Age > 25) 7 { 8 targetList.Add(item); 9 } 10 } 11 }
Linq查询和Lambda表达式查询:
1 // 2 // 摘要: 3 // 基于谓词筛选值序列。 4 // 5 // 参数: 6 // source: 7 // 要筛选的 System.Collections.Generic.IEnumerable<T>。 8 // 9 // predicate: 10 // 用于测试每个元素是否满足条件的函数。 11 // 12 // 类型参数: 13 // TSource: 14 // source 中的元素的类型。 15 // 16 // 返回结果: 17 // 一个 System.Collections.Generic.IEnumerable<T>,包含输入序列中满足条件的元素。 18 // 19 // 异常: 20 // System.ArgumentNullException: 21 // source 或 predicate 为 null。 22 public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
注:Where本身是一个扩展方法.
Lambda
1 { 2 Console.WriteLine("**************************"); 3 var targetList = studentList.Where<Student>(t => t.Age > 25);//陈述式 4 foreach (var item in targetList) 5 { 6 Console.WriteLine(" {0} {1}", item.Age, item.Name); 7 } 8 Console.WriteLine("**************************"); 9
Linq
1 Console.WriteLine("**************************"); 2 var list = from s in studentList 3 where s.Age > 25 4 select s; 5 foreach (var item in list) 6 { 7 Console.WriteLine(" {0} {1}", item.Age, item.Name); 8 }
为了弄懂原理,请看下面:
7. Lambda查询模拟器:
this IEnumerable<TSource> source 是数据源
Func<TSource, bool> predicate 是查找的方法,第一个参数是传入参数in,后一个是返回类型-用于判断.
1 public static class ElevenExtend 2 { 3 public static IEnumerable<TSource> ElevenWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 4 { 5 if (source == null) throw new Exception("null"); 6 7 List<TSource> tList = new List<TSource>(); 8 9 foreach (var item in source) 10 { 11 if (predicate.Invoke(item)) //调用时会返回一个bool 12 tList.Add(item); 13 } 14 return tList; 15 } 16 }
1 private static bool CheckStudentAge(Student student) 2 { 3 return student.Age > 25; 4 }
调用:
1 Func<Student, bool> func = new Func<Student, bool>(CheckStudentAge); //t => t.Age > 25; 2 var targetListEleven = studentList.ElevenWhere<Student>(func);//陈述式
foreach (var item in targetListEleven) { Console.WriteLine(" {0} {1}", item.Age, item.Name); }
8. 其他的查询:
1 { 2 Console.WriteLine("**************************"); 3 var targetList =
studentList.Where<Student>(t => t.Age > 25 || t.Name.Contains("信仰") || new int[] { 1, 2 }.Contains(t.ClassId));//陈述式 4 foreach (var item in targetList) 5 { 6 Console.WriteLine(" {0} {1}", item.Age, item.Name); 7 } 8 }
1 // 2 // 摘要: 3 // 将序列中的每个元素投影到新表中。 4 // 5 // 参数: 6 // source: 7 // 一个值序列,要对该序列调用转换函数。 8 // 9 // selector: 10 // 应用于每个元素的转换函数。 11 // 12 // 类型参数: 13 // TSource: 14 // source 中的元素的类型。 15 // 16 // TResult: 17 // selector 返回的值的类型。 18 // 19 // 返回结果: 20 // 一个 System.Collections.Generic.IEnumerable<T>,其元素为对 source 的每个元素调用转换函数的结果。 21 // 22 // 异常: 23 // System.ArgumentNullException: 24 // source 或 selector 为 null。 25 public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);
1 { 2 var list = studentList.Select(s => new 3 { 4 IdAge = string.Format("{0}_{1}", s.Id, s.Age), 5 Name = s.Name 6 }); 7 Console.WriteLine("**************************"); 8 foreach (var student in list) 9 { 10 Console.WriteLine("Name={0} Age={1}", student.Name, student.IdAge); 11 } 12 }
对应的linq
1 { 2 var list = from student in studentList 3 //where student.Age > 25 4 select new 5 { 6 IdAge = string.Format("{0}_{1}", student.Id, student.Age), 7 Name = student.Name 8 };//语法糖 9 10 Console.WriteLine("**************************"); 11 foreach (var student in list) 12 { 13 Console.WriteLine("Name={0} Age={1}", student.Name, student.IdAge); 14 } 15 }
1 { 2 Console.WriteLine("**************************"); 3 foreach (var student in studentList.Where<Student>(s => s.ClassId == 2 && s.Id < 4) 4 .Select<Student, Student>(s =>
//Skip是跳过 Take是获取
new Student { Age = s.Age, Name = string.Format("{0}_{1}", s.Name, s.Id) }) 5 .OrderBy<Student, int>(s => s.Id) 6 .OrderByDescending<Student, int>(s => s.Age) 7 .Skip<Student>(1)//跳过1个 8 .Take<Student>(5))//获取5个 9 { 10 Console.WriteLine("Name={0} Age={1}", student.Name, student.Age); 11 } 12 }
注:linq查询编译后还是调用的Lambda表达式.
以上是关于Lambda表达式的本质是匿名函数的主要内容,如果未能解决你的问题,请参考以下文章