• 拉姆达表达式


    拉姆达表达式学习(1)

      我曾经遇到一个项目,项目里面需要经常对一系列的同类型集合进行操作,如对集合进行增加元素,删除集合的指定索引的元素等等.
      我们可以使用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 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 /// <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 { getset; }
     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     public int AllLen()
     2         {
     3             //StringBuilder stbTemp = new StringBuilder();
     4             //foreach (var item in _List)
     5             //{
     6             //    stbTemp.Append(item);
     7             //}
     8             //return stbTemp.Length;
     9 
    10             StringBuilder stbTemp = new StringBuilder();
    11             var type = typeof(T);
    12             if (type == typeof(string))
    13             {
    14                 foreach (var item in _List)
    15                 {
    16                     stbTemp.Append(item);
    17                     stbTemp.Append("<BR>");
    18                 }
    19                 return stbTemp.Length;
    20             }
    21             if (type == typeof(int))
    22             {
    23                 int intSum = 0;
    24                 foreach (var item in _List)
    25                 {
    26                     intSum += int.Parse(item.ToString());
    27                 }
    28                 return stbTemp.Length;
    29             }
    30 
    31             /*  这里可能还需要根据不同的类型进行不同的处理
    32              */
    33             return 0;
    34         }

     

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

     

    代码

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

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

     

    代码

     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        /*
    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 { getset; }

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

     

    代码

     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 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         }

     

     

    具体我们来看看拉姆达表达式的用法!
    拉姆达表达式由三个部分组成,=>是拉姆达中固定的符号,必须出现!
    =>
    左边的表达式是一个参数列表,是一组没有类型的字符(字符怎么写随意!只要符合命名规范就好了),每个字符表示一个参数,每个参数之间使用逗号分割.
    :
     
    如果有三个参数,则表达式为(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      public void Main()
     2         {
     3              var intSumTemp = Sum((tempInt) => { return tempInt + 1; });
     4         }
     5 
     6         public int Sum(Func<intint> 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);

    拉姆达表达式学习(2)

    .net3.5里面,委托的定义和实现被大大的简化了!使用关键字FuncAction就可以定义一个委托,使用拉姆达表达式就可以实现一个具体的委托.
    Func
    关键字是用来定义一个有返回值的委托,它一共有五个重载,我们介绍其中的三个
    1 public delegate TResult Func<TResult>();
     
    这表示一个没有参数,只有一个返回值的委托,返回值的类型就是TResult(泛型)

     

    代码

     1  public class test
     2     {
     3         /// <summary>
     4         /// 定义一个委托
     5         /// </summary>
     6         public Func<string> _GetName;
     7         /// <summary>
     8         /// 一个普通的没有参数,有返回值的方法
     9         /// </summary>
    10         /// <returns></returns>
    11         public string GetName()
    12         {
    13             return "张三";
    14         }
    15         public void Main()
    16         {
    17             //3.5以前的委托的实现,直接赋值
    18             _GetName = GetName;
    19 
    20             //拉姆达表达式的实现方法
    21             _GetName = (
    22                 ()          //因为这个委托没参数,所以参数列表没有东西
    23                     =>      //拉姆达表达式的符号
    24                 {           //大括号的代码段表示具体的委托的实现
    25                     return "还是张三";
    26                 });
    27             //拉姆达表达式的简写,如果委托的实现代码段中只有一句return 则可以省略代码段最外面的大括号,return关键字
    28             _GetName = () => "总是张三";
    29             //调用
    30             string MyName = _GetName();
    31         }
    32     }

     

    2 public delegate TResult Func<T, TResult>(T arg);
     
    这表示有且仅有一个参数,并且有返回值的委托.

     

    代码

     1  public class test
     2     {
     3         /// <summary>
     4         /// 定义一个委托,有一个参数和一个返回值
     5         /// </summary>
     6         public Func<stringstring> _GetName;
     7         /// <summary>
     8         /// 有一个参数的方法
     9         /// </summary>
    10         /// <param name="strName">这是一个参数!</param>
    11         /// <returns>这是一个返回值</returns>
    12         public string GetName(string strName)
    13         {
    14             return strName;
    15         }
    16         public void Main()
    17         {
    18             //3.5以前的委托的实现,直接赋值
    19             _GetName = GetName;
    20 
    21             //拉姆达表达式的实现方法
    22             _GetName = (
    23                 (S)          //有一个参数!所以参数列表里面有一个东西,这个东西随大家高兴叫个阿猫阿狗都行!只要符合规范
    24                     =>      //拉姆达表达式的符号
    25                 {           //大括号的代码段表示具体的委托的实现
    26                     return "还是" + S;
    27                 });
    28             //拉姆达表达式的简写,如果委托的实现代码段中只有一句return 则可以省略代码段最外面的大括号,return关键字
    29             _GetName = (abc) => "总是" + abc;
    30             //调用
    31             string MyName = _GetName("张三");
    32         }
    33     }

     

    3 public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
     
    这表示有且仅有两个参数,并且有返回值的委托.

     

    代码

     1  public class test
     2     {
     3         /// <summary>
     4         /// 定义一个委托,有一个参数和一个返回值
     5         /// </summary>
     6         public Func<stringintstring> _GetName;
     7         /// <summary>
     8         /// 这是一个有两个参数的方法,方法的参数类型的顺序必须和委托的参数类型顺序一致
     9         /// </summary>
    10         /// <param name="strName">第一个是字符类型</param>
    11         /// <param name="intAGE">第二个是整形,请不要颠倒类型!</param>
    12         /// <returns>返回一个字符串,对应委托的最后一个参数</returns>
    13         public string GetName(string strName, int intAGE)
    14         {
    15             return string.Format("{0}的年龄是{1}", strName, intAGE);
    16         }
    17         public void Main()
    18         {
    19             //3.5以前的委托的实现,直接赋值
    20             _GetName = GetName;
    21 
    22             //拉姆达表达式的实现方法
    23             _GetName = (
    24                 (S, W)          //有一个参数!所以参数列表里面有一个东西,这个东西随大家高兴叫个阿猫阿狗都行!只要符合规范
    25                     =>      //拉姆达表达式的符号
    26                 {           //大括号的代码段表示具体的委托的实现
    27                     return string.Format("{0}的年龄是{1}", S, W);
    28                 });
    29             //拉姆达表达式的简写,如果委托的实现代码段中只有一句return 则可以省略代码段最外面的大括号,return关键字
    30             _GetName = (abc, efd) => string.Format("{0}的年龄是{1}", abc, efd);
    31             //调用
    32             string MyName = _GetName("张三"33);
    33         }
    34     }

     

    Action关键字用来定义一个没有返回值的方法,它有一个非泛型方法,和四个泛型方法,一共五种.Actionfunc的区别就在于一个没有返回值,一个有返回值!其他的都一样!就好像VBsubfunction一样!
    1 public delegate void Action();
    没有参数也没有返回值

     

    代码

     1 public class test
     2     {
     3         /// <summary>
     4         /// 定义一个委托,没有返回值也没有参数
     5         /// </summary>
     6         public Action _GetName;
     7 
     8         public void GetName()
     9         {
    10             System.Windows.Forms.MessageBox.Show("没有参数也没有返回值,我只要自己显示了!");
    11         }
    12         public void Main()
    13         {
    14             //3.5以前的委托的实现,直接赋值
    15             _GetName = GetName;
    16 
    17             //拉姆达表达式的实现方法
    18             _GetName = (
    19                 ()
    20                     =>      //拉姆达表达式的符号
    21                 {           //大括号的代码段表示具体的委托的实现
    22                     System.Windows.Forms.MessageBox.Show("没有参数也没有返回值,我只要自己显示了!");
    23                 });
    24             //因为action没有返回值,所以下面的简写方式是错误的
    25             //_GetName = () => System.Windows.Forms.MessageBox.Show("没有参数也没有返回值,我只要自己显示了!"); 
    26             //调用
    27             _GetName();
    28         }
    29     }

    2  public delegate void Action<T>(T obj);
    有一个参数但没有返回值

     

     

    代码

     1 public class test
     2     {
     3         /// <summary>
     4         /// 定义一个委托,没有返回值也没有参数
     5         /// </summary>
     6         public Action<bool> _GetName;
     7 
     8         public void GetName(bool blnShow)
     9         {
    10             if (blnShow)
    11             {
    12                 System.Windows.Forms.MessageBox.Show("要我显示就显示,多没面子");
    13             }
    14             else
    15             {
    16                 System.Windows.Forms.MessageBox.Show("不要我显示,我偏要显示");
    17             }
    18         }
    19         public void Main()
    20         {
    21             //3.5以前的委托的实现,直接赋值
    22             _GetName = GetName;
    23 
    24             //拉姆达表达式的实现方法
    25             _GetName = (
    26                 (b)
    27                     =>      //拉姆达表达式的符号
    28                 {           //大括号的代码段表示具体的委托的实现
    29                     if (b)
    30                     {
    31                         System.Windows.Forms.MessageBox.Show("要我显示就显示,多没面子");
    32                     }
    33                     else
    34                     {
    35                         System.Windows.Forms.MessageBox.Show("不要我显示,我偏要显示");
    36                     }
    37                 });
    38 
    39             _GetName(true);
    40         }
    41     }

     

     

     


    不过通常funcaction并不是单独定义,然后使用,而是当作某个方法的参数的类型!

     

  • 相关阅读:
    Flutter 步骤进度组件
    程序员到底要不要学习框架、库和工具
    Flutter 吐血整理组件继承关系图
    超过百万的StackOverflow Flutter 问题
    Flutter 实现网易云音乐字幕
    Flutter 实现虎牙/斗鱼 弹幕效果
    Flutter AbsorbPointer 与 IgnorePointer的区别
    《Flutter 小技巧》一行禁用App,一行置灰App,致敬
    Python 任务自动化工具:nox 的配置与 API
    Flask 作者 Armin Ronacher:我不觉得有异步压力
  • 原文地址:https://www.cnblogs.com/shenfengok/p/2205363.html
Copyright © 2020-2023  润新知