zoukankan      html  css  js  c++  java
  • C#中委托、匿名函数、Lambda表达式的一些个人理解

    0x01定义一个委托,相当于定义一个可以存储方法的特殊变量类型

    下面我们看具体的代码,通过代码更好理解

    delegate void IntMethodInvoker(int x);
    

    这行代码就是声明一个委托,其中delegate是关键字,表示声明一个委托,void是要存储的方法的返回类型,IntMethodInvoker是声明的委托类型名字,结合最开始的那句话就是自定义的类书变量类型名,int x则是要存储的方法的返回类型


    这样一个委托可以存放哪些方法呢?

    只要返回类型一致参数列表一致的方法都能存储

    在这个例子中,就是返回类型为void,有一个int形参的方法

    void test(int t)
    {
        Console.WriteLine("Just a test" + t )
    }
    

    如这样的test方法就可以存储到IntMethodInvoker委托的实例中

    委托是一种特殊类型的对象,定义好委托之后就可以创建它的实例了然后存储方法

    IntMethodInvoker DelegateTest = test;
    

    这行代码即将test方法的地址存放到IntMethodInvoker委托的实例DelegateTest中,在以后只需要调用DelegateTest就能执行test方法。

    DelegateTest(32);
    

    这行代码与test(32)效果相同


    委托可以添加多个方法引用,添加多个方法引用的委托叫多播委托

    添加多个方法引用使用+=,若要删除添加的方法引用使用-=

    0x02使用委托可以将方法当作参数传递

    既然前面说了委托类似于定义一个可以存储方法的特殊变量类型,那么我们也可以将这个特殊类型作为方法的形参,将一个方法引用添加到委托实例中,然后将委托实例作为另一个接受委托类型参数的方法的实参,就达到了将方法传递给另一个方法的效果

    class Program
    {
    
        static void Main(string[] args)
        {
            Test test = new Test();
            Test.TestDelegate testDelegate = new Test.TestDelegate(test.Fun);
    
            test.KK(testDelegate);
        }
    }
    class Test
    {
        public delegate void TestDelegate();
    
        public void Fun()
        {
            Console.WriteLine("这是一个简单的方法!");
        }
        public void KK(TestDelegate testDelegate)
        {
            Console.WriteLine("这是一个接收委托的方法");
            testDelegate();
        }
    }
    

    这是一个将委托作为参数,将一个方法传递给另一个方法的例子

    在这个例子中,先声明了一个Test实例,然后声明了一个TestDelegate委托实例testDelegate

    testDelegate委托包含了test.Fun()的引用,这时并没有调用test.Fun(),只是保存了引用

    接下来执行test.KK(testDelegate),这时testDelegate委托作为形参传递到了KK方法中

    KK方法在调用testDelegate();时,委托执行Fun方法

    所以最后的执行结果是

    这是一个接收委托的方法
    这是一个简单的方法!

    0x03Func<T>Action<T>

    委托非常常用,所以.Net内置了两个委托类型,这样我们就不用自己去声明委托了

    Action<T>泛型委托,表示引用一个void返回类型的方法。这个委托存在不同的变体,可以接受需要0 ~ 16个参数的方法

    Func<T>泛型委托,与Action<T>相似,但是表示引用一个有一个返回值类型的方法。Func<T>同样可以接收0 ~ 16个参数的方法,默认最后一个是返回类型,即Fun<T>最多有十七位参数

    Func<string,string,int>
    

    这个Func表示可以接收一个参数列表为两个string,返回一个int的方法。

    0x03Lambda和匿名方法

    匿名方法:

    Func<string, string> anonDel = delegate (string param)
    {
        param += mid;
        param += " and this was added to the string.";
        return param;
    };
    

    匿名方法的作用:

    委托是存储方法的引用,也就是说,要用委托,就必须要先有方法,但是实际上有很多时候委托所存储的方法引用只会在委托或者事件(事件基于委托)中使用,这时候我们单独定义一个方法很麻烦,这时候就可以使用匿名方法,上方就是一个匿名方法,我们看右边

    delegate (string param)
    {
        param += mid;
        param += " and this was added to the string.";
        return param;
    };
    

    这个就是匿名方法,使用delegate关键字,如果我们把delegate换成一个普通的名字

    KK (string param)
    {
        param += mid;
        param += " and this was added to the string.";
        return param;
    };
    

    这就是一个普通的方法(结尾的分号是Fun委托赋值语句的结尾),所以匿名方法就是一个普通的方法将方法名去掉换成delegate,以达到简化代码的目的

    Func<string, string> anonDel = 
    
    delegate (string param)
    {
        param += mid;
        param += " and this was added to the string.";
        return param;
    };
    

    这样看是不是很好理解了

    Lambda表达式:

    在我的理解中,Lambda表达式其实是为了简化匿名方法

    我们依然用上面的代码

    //匿名方法
    delegate (string param)
    {
        param += mid;
        param += " and this was added to the string.";
        return param;
    }
    
    
    //Lambda表达式
    (string pram) =>
    {
        param += mid;
        param += " and this was added to the string.";
        return param;
    }
    

    这两个是等价版本, =>就是Lambda运算符,现在我们看它的两边是什么,左边是参数列表,右边是方法体。

    这个Lambda其实有一点复杂了,通常我们遇到的Lambda会更简化

    • 如果只有一个参数,只需要参数名就足够了,即这个Lambda中,可以将(string pram)改写为pram
    • 如果方法体只有一行语句,那么在方法块中就不需要花括号和return语句

    举个例子

    Func<double,double> square = (double x) =>
    {
        return x*x;
    };
    

    这个Lambda表达式可以简写为

    Func<double,double> square = x => x*x
    

    Lambda表达式的闭包问题

    这里就一句话,在Lambda表达式使用了外部的变量(不是Lambda表达式内的变量),外部的变量的值在调用时决定,而不是定义Lambda表达式时决定

    int someVal = 5;
    Func<int, int> ZZ = x => x + someVal;
    someVal = 7;
    Console.WriteLine(ZZ(3));
    

    最后输出的时7,因为ZZ委托调用Lambda表达式时someVal已经等于7了

  • 相关阅读:
    对接天猫精灵X1 (https 的申请)
    第二个 SignalR,可以私聊的聊天室
    抽象工厂模式
    装饰者模式
    Signal 第一个简单Demo
    策略模式
    完美删除vector的内容与释放内存
    VC++的窗口句柄和窗口ID
    如何让模态对话画框达到非模态对话框 焦点无限制效果
    指针初始化为NULL的作用
  • 原文地址:https://www.cnblogs.com/wujuncheng/p/12700157.html
Copyright © 2011-2022 走看看