首页 > 代码库 > Lambda表达式的本质是匿名函数

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         } 
ShowPerson
技术分享
 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 Class18     {19         public int Id { get; set; }20         public string Name { get; set; }21     }
Student
技术分享
 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 System2 {3     // 摘要: 4     //     封装一个方法,该方法不具有参数并且不返回值。5     [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]6     public delegate void Action();7 }
Action(一个参数)
技术分享
 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 }
Action(in T)

 

技术分享
  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 }
系统封装-最多16个参数

实例化:

1             //接受0到16个参数的  无返回值 泛型委托2             Action act1 = () => Console.WriteLine("123"); //13             Action<string> act2 = t => { };//24             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 }
一个in,一个out
技术分享
  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 }
系统最多16个in参数

不过,不管怎么变,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);
如果16个参数不够的话
1 //接受0到16个参数的  带返回值 泛型委托2             Func<int> func1 = () => DateTime.Now.Millisecond;//4--返回int类型
        //下面都返回string类型3 Func<int,
           string> func2 = t => DateTime.Now.Millisecond.ToString();//54 Func<Student, Class, int, long, Student, Class, int, long, Student, Class, int, long, Student, Class, int, long,
string> func3 = null;//65 //调用自己写的,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             else19             {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=212                 },13                 new Student()14                 {15                     Id=2,16                     Name=" LTS_信仰I(196-LTS_信仰I-男-深圳)",17                     Age=36,18                     ClassId=119                 },20                 new Student()21                 {22                     Id=3,23                     Name="ObjectIsNotFound",24                     Age=24,25                     ClassId=226                 },27                 new Student()28                 {29                     Id=4,30                     Name="落单的候鸟",31                     Age=25,32                     ClassId=233                 },34                 new Student()35                 {36                     Id=1,37                     Name="夜的乐章",38                     Age=31,39                     ClassId=240                 },41                 new Student()42                 {43                     Id=1,44                     Name="知心dě朋友=(357-杰仔-男-广州)",45                     Age=18,46                     ClassId=247                 },48                 new Student()49                 {50                     Id=1,51                     Name="",52                     Age=33,53                     ClassId=254                 },55                 new Student()56                 {57                     Id=1,58                     Name="小逸",59                     Age=28,60                     ClassId=261                 },62                   new Student()63                 {64                     Id=1,65                     Name="季雨林",66                     Age=27,67                     ClassId=268                 },69                   new Student()70                 {71                     Id=1,72                     Name="dean",73                     Age=34,74                     ClassId=275                 },76                    new Student()77                 {78                     Id=1,79                     Name="yup_h",80                     Age=21,81                     ClassId=182                 }83             };84             #endregion 初始化数据85             return studentList;86         }
Linq用到的数据

普通程序员一般会想的方法:

 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

注: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 studentList3                            where s.Age > 254                            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)) //调用时会返回一个bool12                     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); 
Select投影查询
 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表达式的本质是匿名函数