拉姆达表达式学习(1)

时间:2021-11-25 18:48:54

  我曾经遇到一个项目,项目里面需要经常对一系列的同类型集合进行操作,如对集合进行增加元素,删除集合的指定索引的元素等等.
  我们可以使用ArrayList来进行.如

 

1  ArrayList stringList = new  ArrayList();
2  stringList.Add( " 大家好 " );
3  stringList.Add( " 你们好 " );
4  stringList.Add( " 同志们好 " );
5  string  str1 = ( string )stringList[ 0 ]; // 取出一个元素后,需要转换一次类型才可以

 

 或者是

 

1  ArrayList intList = new  ArrayList();
2  intList.Add( 6 );
3  intList.Add( 8 );
4  intList.Add( 66 );
5  int  int1 = ( int )intList[ 0 ]; // 取出一个元素后,需要转换一次类型才可以

 

  但是ArrayList中的每个元素的类型都是Object(stringList[0]的类型是Object]),这意味着我们每一次的操作,其实都进行了隐式的类型转换,加入资料是把普通类型转换成Object类型,取出资料是把Object类型转换成普通类型.
  于是我在想象,如果有一种数组类型,在定义的时候,可以给出每个元素具体的类型,并且在赋值或者取值的时候,就是完全按照这个类型进行操作该多好.
  在.net2.0里面,我找到了List这个类型.List是一个泛型,我们看看List的使用

 

拉姆达表达式学习(1)拉姆达表达式学习(1)代码
1  List < string >  stringList  =   new  List < string > ();
2  stringList.Add( " 大家好 " );
3  string  str1  =  stringList[ 0 ]; // 直接赋值成功!因为取出来的就是string对象
4  // 或者是
5  List < int >  intList  =   new  List < int > ();
6  intList.Add( 8 );
7  int  int1  =  intList[ 0 ]; // 直接赋值成功!因为取出来的就是int对象

 

 

  大家可以看出,List在实例化的时候就需要定义一个类型,也就是尖括号中间的东西,在增加元素,或者获取元素的时候,操作的都是最开始定义的那种类型.List便是传说中的泛型类型.
  泛型可以用在方法上,也可以用在类上.如果看到某个方法或者类后面带有尖括号的,那么这个肯定就是泛型了.

  现在,我找到了能够有效的存储我要操作的集合的类型,那么我们要解决一些操作了.
  我需要对集合进行一个连接输出(把所有的元素连接在一起,每个元素之间使用<BR>来分割),还需要知道所有元素的总长度.显然,光一个List类型是解决不了问题的.于是我自己定义了一个自己的泛型类型

 

 

拉姆达表达式学习(1)拉姆达表达式学习(1)代码
 1  ///   <summary>
 2       ///  这是一个泛型类,类名后面接着一个尖括号里面的那个t,是我们自己定义的,如果你高兴,你可以定义w,y,z,WC都没有问题!
 3       ///  这个T表示说我们在实例化类的时候,需要告诉类,我们是用哪一种类型来进行操作.
 4       ///   </summary>
 5       ///   <typeparam name="T"></typeparam>
 6       public   class  MyList < T >
 7      {
 8           public  List < T >  _List {  get set ; }
 9           public  MyList()
10          {
11               this ._List  =   new  List < T > ();
12          }
13           ///   <summary>
14           ///  用来连接所有元素用
15           ///   </summary>
16           ///   <returns> 连接后的字符串 </returns>
17           public   string  JoinOut()
18          {
19              StringBuilder stbTemp  =   new  StringBuilder();
20               foreach  (var item  in  _List)
21              {
22                  stbTemp.Append(item);
23                  stbTemp.Append( " <BR> " );
24              }
25               return  stbTemp.ToString();
26          }
27           ///   <summary>
28           ///  所有元素的长度
29           ///   </summary>
30           ///   <returns> 元素的整体长度 </returns>
31           public   int  AllLen()
32          {
33              StringBuilder stbTemp  =   new  StringBuilder();
34               foreach  (var item  in  _List)
35              {
36                  stbTemp.Append(item);
37              }
38               return  stbTemp.Length;
39          }
40 
41      }

 

但是如果我在求元素长度的时候,要求如果是stirng则返回所有元素的长度,而是int的时候,则返回所有元素的和.于是我重写了AllLen方法

 

拉姆达表达式学习(1)拉姆达表达式学习(1)代码

 

 我在整个项目中,会负责编写公用类库.我不知道其他前台编码人员需要什么样子的操作.并且前台编码人员会各处一些稀奇古怪的需求我,要我实现,如他想接受一系列的bool类型,然后判断所有结果为True的数量,或者传入一系列的日期,判断所有星期一的日期有多少个...等等.我比较懒,并且我非常不愿意去修改我已经写好的类库.所以我又对Allen进行了一次修改.

 

拉姆达表达式学习(1)拉姆达表达式学习(1)代码
 1       // 写一个委托,谁愿意做什么操作就自己写去,哥不管了!
 2       public   delegate   int  delegateAllLen < T > (List < T >  list);
 3           // 写一个委托,谁愿意做什么操作就自己写去,哥不管了!
 4           public  delegateAllLen < T >  FuncAllLen {  get set ; }
 5           public   int  AllLen()
 6          {
 7               if  (FuncAllLen  !=   null )
 8              {
 9                   return  FuncAllLen(_List);
10              }
11               return   0 ;
12          }

我告诉前台编码人员,你们想做什么就先去实现委托FuncAllLen.然后调用AllLen方法.

 

拉姆达表达式学习(1)拉姆达表达式学习(1)代码
 1       ///   <summary>
 2           ///  委托的实现
 3           ///   </summary>
 4           ///   <param name="bln"></param>
 5           ///   <returns></returns>
 6           public   int  Temp(List < bool >  bln)
 7          {
 8               int  i  =   0 ;
 9               foreach  (var item  in  bln)
10              {
11                   if  (item) i ++ ;
12              }
13               return  i;
14          }
15 
16           public   void  Main()
17          {
18              var list  =   new  MyList < bool > ();
19 
20              list._List.Add( true );
21              list._List.Add( false );
22              list._List.Add( true );
23               /// 实现委托
24              list.FuncAllLen  +=  Temp;
25              MessageBox.Show(list.AllLen().ToString());
26          }
27 
28 

现在我就轻松多了,可以去睡大觉了!所有的具体操作,前台编码人员自己去实现FuncAllLen 这个委托去!我全部不管了!哈哈哈!
不过这样写可能还是有有点难以理解.一会定义一个delegate int delegateAllLen<T>(List<T> list);一会又是delegateAllLen<T> FuncAllLen { get; set; },都不知道那个是那个....
于是我采用C#3.5中委托的写法

 

拉姆达表达式学习(1)拉姆达表达式学习(1)代码
1          /*
2          public delegate int delegateAllLen<T>(List<T> list);
3          public delegateAllLen<T> FuncAllLen { get; set; }
4          以上这两句,可以简写成下面的一句!
5            */
6           public  Func < List < T > int >  FuncAllLen {  get set ; }

调用的方法和以前一样,可是编码人员告诉我:这样你方便了,我们可就麻烦了,每次都要记得在使用AllLen方法的时候,都要先把委托实现了.特别是新来的人,总是记不住.
正好,最近我在学习Linq,c#3.5中推出了拉姆达表达式,可以让委托更简单的实现!于是我最后一次重写AllLen方法

 

拉姆达表达式学习(1)拉姆达表达式学习(1)代码
 1       // 我要使用最先进,最流行的拉姆达表达式!所以下面的这行委托我不需要了!哈哈哈哈
 2       // public Func<List<T>, int> FuncAllLen { get; set; }
 3 
 4           // 其实我把上面的委托定义放到函数里面当参数了....
 5           public   int  AllLen(Func < List < T > int >  FuncAllLen)
 6          {
 7               if  (FuncAllLen  !=   null )
 8              {
 9                   return  FuncAllLen(_List);
10              }
11               return   0 ;
12          }

 

最后我们看看调用的方法

拉姆达表达式学习(1)拉姆达表达式学习(1)代码
拉姆达表达式学习(1)
 1  public   void  Main()
 2          {
 3              var list  =   new  MyList < bool > ();
 4 
 5              list._List.Add( true );
 6              list._List.Add( false );
 7              list._List.Add( true );
 8           // 传说中的拉姆达表达式出现了!!!!!!
 9               int  intRef  =  list.AllLen(
10                  PList  =>
11                  {
12                       int  i  =   0 ;
13                       foreach  (var item  in  PList)
14                      {
15                           if  (item) i ++ ;
16                      }
17                       return  i;
18                  });
19          }
拉姆达表达式学习(1)

 

 

具体我们来看看拉姆达表达式的用法!
拉姆达表达式由三个部分组成,=>是拉姆达中固定的符号,必须出现!
=>左边的表达式是一个参数列表,是一组没有类型的字符(字符怎么写随意!只要符合命名规范就好了),每个字符表示一个参数,每个参数之间使用逗号分割.
如:
 如果有三个参数,则表达式为(A,B,C),或者是(P1,P2,P3),
=>右边的是具体要实现的代码段,代码段里面可以使用参数列表中的参数进行各种运算.
如:
{return P1+P2+p3;}
合起来就是 (P1,P2,P3)=>{return P1+P2+P3;}
如果参数只有一个,那么省去小括号:P1=>{return P1+10;}
如果具体的实现代码只有一句返回语句,则可以简写成 P1=>P1+10;

一定要注意,拉姆达表达式只是一个委托的定义而已,当程序运行到拉姆达表达式的时候,拉姆达表达式里面的语句是不会被立刻执行的,很多人在初学拉姆达或者委托的时候都会犯这种错误.
如:

 

拉姆达表达式学习(1)拉姆达表达式学习(1)代码
 1        public   void  Main()
 2          {
 3               var intSumTemp  =  Sum((tempInt)  =>  {  return  tempInt  +   1 ; });
 4          }
 5 
 6           public   int  Sum(Func < int int >  func)
 7          {
 8          var int1 = 5 ;
 9          int1 += 5 ;
10              var intTemp  =  func(int1);
11               return  intTemp  *  intTemp;
12          }

 

 

上面的intSumTemp的结果是121.
运行的顺序是:首先调用Sum方法而不会去执行拉姆达表达式.
然后得到int1=10的结果(5+5),
接着需要运行func了,并且知道func的参数值是int1,即10.
那么func是通过拉姆达表达式定义的,所以这个时候,我们把10传入拉姆大表达式中,进行运算得到11(10+1)
方法最后是一个平方操作.结果为121(11*11)

知道拉姆达的写法,和使用的方法,那么我们在什么情况下可以使用拉姆达表达式能?
当我们在使用一个方法,方法的参数是Func,或Action,那么就可以使用拉姆达表达式了!
我们拿linq里面的方法举例!
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
可写成  var temp=_List.Where(P=>{return true;});
public static int Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector);
可写成  var temp=_List.Sum(P=>P.count);

本段作为讲解拉姆达表达式的一个引文!下一章会给大家介绍一下Func和Action