委托学习总结(二)匿名方法和lambda表达式

时间:2022-05-02 19:58:53

  之前总结了委托这个困惑着大多初学者的概念,继续来学习匿名方法和lambda表达式

(1)我们之前写了这样一段代码

//自定义一个委托
        public delegate int Expression(int a, int b);
        class Program
        {
            static void Main(string[] args)
            {
                //(2)委托扩展
                //Expression ex = Add;
                //Calculate(ex, 25, 10);
                Calculate(Add, 25, 10);
            }
            static int Add(int a, int b)
            {
                return a + b;
            }
            static int Divide(int a, int b)
            {
                return a / b;
            }
            static int subtract(int a, int b)
            {
                return a - b;
            }
            static int multiply(int a, int b)
            {
                return a * b;
            }
            static int GetAdd(int a, int b)
            {
                return a + b;
            }
            static void Calculate(Expression ex, int a, int b)
            {
                Console.WriteLine(ex(a, b) + "\n");
            }
        }

  我们既然之前说到已经把Calculate封装起来了,那么这里我们就把Calculate方法看成一个已经封装好了的方法(这里只是为了举例,并不是指Calculate方法真的已经完全封装好了),那么既然Calculate已经不能改了,那么四个加减乘除方法有什么可以优化的地方呢?,我们把a - b,a * b,a / b等等可以写的计算表达式写成不同的方法,而且还分别不同命名,这样做是不是有点过于“浪费”了勒,我们写这样四个方法真正要实现的目的就是能让四个方法传递到另一个方法的某一个语句块中被执行,这段要被传递的语句块有没有名字其实并不重要,那么这里就要引出一位今天的主人公了,他就是匿名方法,很多人刚接触这个概念时可能会一头雾水,而且大多教科书都喜欢把它放在委托的后面讲,就会觉得这个东西很神奇,其实匿名方法并没有那么复杂,不明白只是因为对这个概念生疏而已,或者说是人的惯性思维,我们在初学时都习惯了约定俗成的认为一个方法必须有名字,有参数,有返回值,其实语言的设计者再设计方法(有的语言也叫函数)的初衷就是增加代码的重用,使代码更灵活而已,不管是方法还是匿名方法,其本质都是一段执行语句,所以顾名思义,匿名方法就是没有名字的一方法,那方法是什么,你可以粗暴的理解为方法就是一段可以通过方法名来调用执行语句,那么匿名方法就是一段没有名字的执行语句,他们都是执行语句。说了这么多我来具体看一下,如何通过匿名方法实现上面的代码

 

//自定义一个委托
    public delegate int Expression(int a, int b);
    class Program
    {
        static void Main(string[] args)
        {
            //(3)匿名方法
            Expression add = delegate (int a, int b) { return a + b; };
            Expression subtract = delegate (int a, int b) { return a - b; };
            Expression multiply = delegate (int a, int b) { return a * b; };
            Expression divide = delegate (int a, int b) { return a / b; };
            Calculate(add, 10, 25);
        }
        
        //static int Add(int a, int b)
        //{
        //    return a + b;
        //}
        //static int Divide(int a, int b)
        //{
        //    return a / b;
        //}
        //static int subtract(int a, int b)
        //{
        //    return a - b;
        //}
        //static int multiply(int a, int b)
        //{
        //    return a * b;
        //}

        static void Calculate(Expression ex, int a, int b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }
    }

 

  这里我们直接对Expression委托类型进行赋值,将四个匿名方法赋值给了Expression的实例,这样我们不必在为每种计算分别写不同的方法了,这样写看上去是不是比之前美观简洁了许多,但是实际代码并没有减少许多,我们可不可以有什么方法,直接写一个表达式传给Calculate方法呢?这里就要引入今天的另一个主角——lambda表达式,说到lambda表达式,你并不要害怕,其实lambda表达式并不是一个全新的概念,它只不过是升级了的匿名方法罢了,很多初学者看到lambda表达式,完全无法想象他与匿名方法,以及委托有什么关系,又会误认为它是一个全新的概念,其实并不是,它只不过是一段更为简洁的匿名方法罢了,也可以它只不过是一段更为简洁的执行语句罢了。下面我们就来通过代码来对比lambda表达式,匿名方法,以及方法+委托

(1)最原始的一种,定义方法,通过委托传递或调用方法

//自定义一个委托
    public delegate int Expression(int a, int b);
    class Program
    {
        static void Main(string[] args)
        {
            Expression ex = Add;
            Calculate(ex, 10, 25);
            //或者直接这样写
            //Calculate(Add, 10, 25);
            Console.ReadKey();
        }

        static int Add(int a, int b)
        {
            return a + b;
        }
        static int Divide(int a, int b)
        {
            return a / b;
        }
        static int subtract(int a, int b)
        {
            return a - b;
        }
        static int multiply(int a, int b)
        {
            return a * b;
        }
        static void Calculate(Expression ex, int a, int b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }
    }

(2)第二种,也就是最上面写的那种,通过委托传递匿名方法

//自定义一个委托
    public delegate int Expression(int a, int b);
    class Program
    {
        static void Main(string[] args)
        {
            Expression add = delegate (int a, int b) { return a + b; };
            Expression subtract = delegate (int a, int b) { return a - b; };
            Expression multiply = delegate (int a, int b) { return a * b; };
            Expression divide = delegate (int a, int b) { return a / b; };
            Calculate(add, 10, 25);
        }

        static void Calculate(Expression ex, int a, int b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }
    }

(2)第三种,进一步简化匿名方法,直接传递lambda表达式

    public delegate int Expression(int a, int b);
    class Program
    {
        static void Main(string[] args)
        {
            Calculate((a, b) => a + b, 10, 25);
            Calculate((a, b) => a - b, 10, 25);
            Calculate((a, b) => a * b, 10, 25);
            Calculate((a, b) => a / b, 10, 25);
        }

        static void Calculate(Expression ex, int a, int b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }
    }

  可能你对第三部的写法还是有些不太明白,为什么(a, b) => a + b连参数类型和返回值都没有了,还是可以编译和执行,系统是如何知道这个表达式的参数类型和返回值的呢?这里我们在方法Calculate定义的时候第一个参数是Expression类型,所以我们既然已经在定义委托时已经规定了Expression的参数个数,参数类型,以及返回值类型,那么我们在写lambda表达式就不必在重复定义类型了,所以参数类型与返回值类型不用重复定义,只是需要注意到是参数个数,当lambda表达式只有一个参数时,表达式的”()“括号可以省略,无参和多参括号都不可以省。

  这就是从委托到lambda表达式一步步的演化,我们的理解也一步步的加深,其实这就是lambda表达式就是C#这门语言不断进化的产物,无论它怎样进化,变得多么简单,它最终的本质还是逃不过那几个字:一段可以被传递的执行语句