• Lambda表达式的诞生过程


    这是一篇很经典的文章,解决了工作中一些使用过但是又不太明白的知识点,今天终于弄明白了。花了一晚上重新整的,坚决要分享出来!!!

    那得从很久很久以前说起了,记得那个时候...

    懵懂的记得从前有个叫委托的东西是那么的高深难懂。

    委托的使用

    例一:

    public delegate void AddDelegate();
            public class Program
            {
                public Program()
                {
                    AddDelegate add = new AddDelegate(Add);
                }
                public void Add()
                {
                    Console.Write("hello");
                }
            }

    什么是委托?

    个人理解:用来传递方法的类型。(用来传递数字的类型有int、float、double,用来传递方法的就有委托

    例二:

     1 public delegate void Callback();
     2         class Program
     3         {
     4             public Program()
     5             {
     6                 SendMail(SavaLogOK, SaveLogErr);
     7             }
     8             public void SendMail(Callback sentResult, Callback errorAction)
     9             {
    10                 //...发送邮件...
    11                 if (true)
    12                     sentResult();  //发送成功
    13                 else
    14                     errorAction();  //发送失败
    15             }
    16 
    17             public void SaveLogErr()
    18             { }
    19             public void SavaLogOK()
    20             { }
    21         }

    又经过了很久很久...

    匿名方法

    很多时候委托接收的方法是一次性的或者方法体是非常简单的...

    例三:

     1 public delegate int AddDelegate(int a, int b);
     2         public class Program
     3         {
     4             public Program()
     5             {
     6                 AddDelegate addTest = new AddDelegate(Add);
     7                 addTest(1,2);//执行方法
     8             }
     9             public int Add(int a, int b)
    10             {
    11                 return a + b;
    12             }
    13         }

    我们可以写成:

    1 public delegate int AddDelegate(int a, int b);
    2         public class Program
    3         {
    4             public Program()
    5             {
    6                 AddDelegate addTest = new AddDelegate(delegate(int a, int b) { return a + b; });
    7             }
    8             
    9         }

    有没有发现我们每次都要定义委托,很多时候签名可能是一样的。这样就没有必要定义重复的。

    然后又过了很久很久...

    Func和Action

    可能老大也觉得我们每次定义委托有点傻,所以干脆在框架内一次定义好所有可能用到的委托。那千变万化的方法签名怎么可能定义得全?没关系,定义成泛型的不就可以了吗。

    先说Func:

     1 public delegate int AddDelegate(int a, int b);//这种委托不用在定义
     2         public class Program
     3         {
     4             public Program()
     5             {
     6                // AddDelegate addTest = new AddDelegate(delegate(int a, int b) { return a + b; });
     7                 Func<int, int, int> addTest = new Func<int, int, int>(delegate(int a, int b) { return a + b; });
     8             }
     9             
    10         }

    细心的朋友可能看到了,Func相对于AddDelegate多定义了一个int。多出了的那个是指的是返回类型。我们F12看对应的定义:

     1  // 摘要:
     2     //     封装一个具有两个参数并返回 TResult 参数指定的类型值的方法。
     3     //
     4     // 参数:
     5     //   arg1:
     6     //     此委托封装的方法的第一个参数。
     7     //
     8     //   arg2:
     9     //     此委托封装的方法的第二个参数。
    10     //
    11     // 类型参数:
    12     //   T1:
    13     //     此委托封装的方法的第一个参数类型。
    14     //
    15     //   T2:
    16     //     此委托封装的方法的第二个参数类型。
    17     //
    18     //   TResult:
    19     //     此委托封装的方法的返回值类型。
    20     //
    21     // 返回结果:
    22     //     此委托封装的方法的返回值。
    23     [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
    24     public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);

    关于上面Func的写法我们可以简写成:(语法糖而已,编译后还是注释的代码

    1  // AddDelegate addTest = new AddDelegate(delegate(int a, int b) { return a + b; });
    2                // Func<int, int, int> addTest = new Func<int, int, int>(delegate(int a, int b) { return a + b; });
    3                 Func<int, int, int> addTest = delegate(int a, int b) { return a + b; };

    再看Action:

     1 class Program
     2         {
     3             public Program()
     4             {
     5                 SendMail(SavaLogOK, SaveLogErr);
     6             }
     7             public void SendMail(Action sentResult, Action errorAction)
     8             {
     9                 //...发送邮件...
    10                 if (true)
    11                     sentResult();  //发送成功
    12                 else
    13                     errorAction();  //发送失败
    14             }
    15 
    16             public void SaveLogErr()
    17             { }
    18             public void SavaLogOK()
    19             { }
    20         }

    提醒:以后如果我们写代码的时候如果写到到delegate...,你要马上想到是否可以用Func或者Action来代替呢?C#4中的Action和Func有16个参数,足够你用了。

    我们等了又等,又过了好久好久...

    Lambda的诞生

    1  public Program()
    2             {
    3                 Func<int, int, int> addTest = delegate(int a, int b) { return a + b; };
    4                 Func<int, int, int> addTest2 = (int a, int b) => { return a + b; };
    5             }

    我XX,这TM就是亲兄弟啊。直接去掉delegate关键字,然后加一个=>就成了lambda表达式了。(=>读作goes to

    我们继续简化:

    1 public Program()
    2             {
    3                 Func<int, int, int> addTest = (int a, int b) => { return a + b; };
    4                 Func<int, int, int> addTest2 = (a, b) => { return a + b; };
    5             }

    丢掉参数类型也是可以的,因为强大的VS可以根据泛型委托Func自己推断出来参数类型。

    还可以简化吗?当然:

    1                 Func<int, int, int> addTest = (int a, int b) => { return a + b; };
    2                 Func<int, int, int> addTest2 = (a, b) => { return a + b; };
    3                 Func<int, int, int> addTest3 = (a, b) => a + b;

    return关键字也不要了,大括号也不要了。(当然,方法体只有单条语句才能怎么做

    现在看起来已经非常接近我们平时用的Lambda表达式了。

    如果传入参数只有一个的话,我们还可以继续简化:

     1 Func<int, int> func = (a) => 2 * a;

    func = a => 2 * a; 

    这就是我们平时见得最多的lambda长相了。

    要长成这样也是有要求的:

    1. 只能有一个传入参数
    2. 方法体只能只一条语句。

    关于第1点,lambda我们平时用得较多的是基于IEnumerable或IQueryable,所以只能有一个参数也就满足了。

    关于第2点,我们使用扩展方法的链式编程来解决。

    如:(用链式来解决第二点)

    1 public Program()
    2             {
    3                 Func<IEnumerable<string>, IEnumerable<string>> fun = t =>
    4                     t.Where(v => v.Length > 10).Reverse().OrderBy(v => v.Length).ToList();
    5             }

    从此,我们过上了幸福的生活...

    借《深入理解C#》中的一图:

    小知识:(异步Lambda)

    1 Func<Student, Task<bool>> func = async t =>
    2 {
    3     await Task.Delay(100);//等待100毫秒
    4     return false;
    5 };

    结束:

    本文简短的说了下lambda表达式在C#中的一步步演化。说的不一定对,轻拍!

    FROM :http://www.cnblogs.com/zhaopei/p/5769782.html

  • 相关阅读:
    从Delegate.CreateDelegate看值类型的实例方法
    c#编译器如何处理匿名委托
    线程静态的几个特点
    Framework 3.5学习笔记
    看看给我用的基类,还有多少人愿意做下去
    .net里面数组的复制
    装饰模式与大接口的装饰模式的思考
    SingleTon的实现与性能
    特性与方法注入
    CLR与浮点数
  • 原文地址:https://www.cnblogs.com/chunhui212/p/5898105.html
Copyright © 2020-2023  润新知