委托与事件、匿名方法与Lambda表达式

时间:2022-04-14 19:04:18

委托:

委托就是把方法或函数以变量的形式来使用。

委托的使用步骤:

定义方法Func() -> 定义委托类型 -> 声明委托类型的变量 -> 注册方法 -> 调用

1、定义方法
    pubic static void Func()
    {
        Consoe.Writeine("我是一个静态的无参无返回值的方法");
    }
2、委托类型(注意)
    -> 语法:
        pubic deegate 方法签名(参数规则);
        -> 拿到方法,删除返回类型前的所有东西与方法参数圆括号后的所有东西
            void Func()
        -> 在剩下的代码前加上[pubic] deegate
            pubic deegate void Func()
        -> 在最后加上分号
            pubic deegate void Func();
        -> 一般在方法名后加上Deegate
            pubic deegate void FuncDeegate();
3、使用,定义委托类型的变量
    -> 该委托的类型名为
        pubic deegate 返回类型 委托类型名(参数);
    -> 定义(一般委托变量用Pasca命名规则)
        FuncDeegate MyFunc;
4、直接将方法名赋值给委托变量
    MyFunc = Func;
    // 一旦完成赋值,就表示MyFunc与Func是同一个方法
    // 就好像"计算机"与"电脑"的关系一样,是一个方法的两个不同名字
5、调用
    方法原本怎么调用,委托变量就怎么调用
        原来:Func();
        现在:MyFunc();

    -> 补充说明
        -> 多个类中如何调用
            在cass MyCass中写一个方法,然后在Main方法中用委托调用
        -> 在定义中系统定义的委托多半以Hander结尾
        -> 委托变量赋值
            MyFunc = Func;
            MyFunc = new FuncDeegate(Func);
            // 委托的本质是一个"类"
        -> 委托的调用
            委托变量();
            委托变量.Invoke();


8、 补充——多态
    -> 实现的最基本的要求
        -> 继承
        -> 子类父类有完"全相同的方法"
            返回类型 方法名(参数)
        -> 父类要virtua或abstract,子类要override

9、 既然委托是类型,我们使用的实际是该类型的变量
    既然是变量就可以当做方法的参数进行传递和返回
    -> 写一个方法,传入一个整数,在方法中使用整数
        pubic static void Func(int num)
        {
            num *= 2;
            Consoe.Writeine(num);
        }
        传入:就在方法后的圆括号中写上对应类型的局部变量
        使用:就是在方法中按照指定规则使用就可以了
    -> 写一个方法,传入一个委托变量,并使用
        pubic void Func(FuncDeegate  aa)
        {
            aa();
        }

10、自定义排序
    -> 排序字符串
        -> 按照字符串的长度排序
        -> 按照字符串的字典排序
    -> 先按照一个规则写一个排序算法(冒泡)
        strs
        for(int i = 0; i < strs.ength - 1; i++)
        {
            for(int j = 0; j < strs.ength - i - 1; j++)
            {
                if(strs[j].ength > strs[j+1].ength)
                {
                    string temp = strs[j];
                    strs[j] = strs[j+1];
                    strs[j+1] = temp;
                }
            }
        }
    -> 思考第二种排序规则是什么,与第一种代码实现的区别是什么
        string.Compare(str1, str2)
        str1 > str2        1
             =            0
             <            -1
        if(string.Compare(strs[j], strs[j+1]) > 0)
        {
            // 交换
        }

多播委托(委托链)
    -> 就好像锁链一样,将多个委托一个一个链在一起,调用第一个委托方法,其后的委托方法依次执行
    -> 语法:
        实现使用:
            委托变量 += 方法名;        // 追加方法,好比在锁链结尾追加锁链
            委托变  量 -= 方法名;        // 移除至指定的方法(不用考虑方法在哪里)
    -> 使用:
        -> 简单的委托链
        -> 带有返回值的委托连
            调用委托连,返回的是最后一个方法的返回值
            如果需要得到委托连中其他方法的返回值,只有一个个调用接收
        -> 如果一个方法出现异常,其后所有方法不在执行

 

 事件(event)
    -> event 是事件定义的关键字
    -> 目标:
        -> 什么是事件
        -> 事件与委托的区别
        -> 如何使用事件(案例)
    -> 第一次接触事件
        WinForm
    -> 事件就是一个委托变量
    -> 等待模块
        // 伪代码
        whie(Consoe.ReadKey().KeyCode != ConsoeInfo.Q)
        {            
        }
    -> 事件与委托的区别
        委托是类型,而刚刚用的是委托的变量(事件是一个特殊的委托变量)
        委托具有灵活性,不安全
            -> 使用委托,注册方法可以使用=和+=
                使用+=叫追加方法,使用=的时候就是注册方法(一旦=以后,委托链中的方法会清空)
            -> 委托在使用的时候为了可以给其添加方法使用了属性或pubic修饰符
                谁都可以调用它
    -> 事件,就是委托变量的阉割版
        -> 不允许使用=赋值,只能使用+=和-=添加和移除方法
        -> 不允许外部调用,只能由内部事件触发方法调用
        
        -> 语法:
            定义委托变量的时候使用
            pubic 委托类型 委托变量;
            改为
            pubic event 委托类型 事件变量;
    -> 说明:
        -> 添加事件

10、窗体传值

11、委托的本质与事件的本质(不作要求,以介绍为主)
    -> 委托的层次级别
        Object
            Deegate
                MuticastDeegate
                    用户定义的委托类型
    -> 委托的内存处理过程
    -> 事件
        -> 事件是一个私有的委托变量和两个方法(remove、add)
            事件的这两个方法可以看做为属性

 

委托和事件的区别:
委托和事件没有可比性,因为委托是类型,事件是对象(可以理解为对委托变量的封装。d),下面说的是委托的对象(用委托方式实现的事件)和(标准的event方式实现)事件的区别。事件的内部是用委托实现的。(举例子:三种实现事件方式的区别)
因为对于事件来讲,外部只能“注册自己+=、注销自己-=”,外界不可以注销其他的注册者,外界不可以主动触发事件,因此如果用Deegate就没法进行上面的控制,因此诞生了事件这种语法。add、remove。
事件是用来阉割委托实例的。事件只能add、remove自己,不能赋值。事件只能+=、-=,不能=、不能外部触发事件。
 
委托与事件总结:
委托的作用:
•占位,在不知道将来要执行的方法的具体代码时,可以先用一个委托变量来代替方法调用(委托的返回值,参数列表要确定)。在实际调用之前,需要为委托赋值,否则为nu。
事件的作用:
•事件的作用与委托变量一样,只是功能上比委托变量有更多的限制。(比如:1.只能通过+=或-=来绑定方法(事件处理程序)2.只能在类内部调用(触发)事件。)
在自定义控件(自己编写控件的时候,会大量用到.编写控件的时候,会写一些事件。但是当这些事件 被触发以后,具体执行的那些事件处理程序是编写控件的人没法确定的。这个时候只能通过事件来占位(调用),具体调用的是哪个方法,由使用控件的人来决定(Cick+=new 委托(方法名);))
 
委托与事件个人理解:
委托是指向具有相同方法签名的方法的变量,可以实现把方法作为参数来传递。(委托类型实质是类,可以理解为:把定义委托类型当成一个用来指向有相同特性的方法的模板,然后定义出具体的变量来指向具体的方法。)
 
事件是委托变量的阉割版,实质是一个私有委托变量和两个委托方法(Add方法和Remove方法),事件是一个受限的委托,只能在定义事件的类的内部去调用,不能在外部直接调用(触发),在外部只能通过+=增加注册方法,通过-=移除指定的方法。
 
二.委托与函数指针的区别
1.委托定义了一种新类,该类代表一组具有特定参数及返回类型的方法。声名了委托类型后,必须创建委托对象(实例化)并使之与特定方法关联。对于静态方法,委托对象直接封装要调用的方法。对于实例方法,必须先创建一个类的实例,然后封装该实例上的一个方法。   
2.委托大体上相当于C中的函数指针。但与函数指针不同的是,委托是面象对象的和类型安全的。   
3.一个委托可以对应多个委托对象,只要方法的签名与委托的最初定义相匹配。委托对象的调用与原方法调用相同。   
4.委托不知道或不关心自己实例对象所封装的方法的细节(什么名字或实现什么功能),只要方法的参数类型和返回类型与该委托的参数类型和返回类型相匹配。
 
匿名方法与Lambda表达式
    -> 调用方法自定义排序
        MySort(strs, 方法);
        // 传统的处理方法,就是先单独写一个判断大小的方法,在调用这个排序
        // 调用MySort方法的使用把比较大小的规则直接写在参数里面
        MySort(strs, {s1.Length > s2.Length});
    -> 匿名方法,没有名字的方法
        -> 就是在代码的执行中定义方法体,运行的时候直接执行(把方法规则写在执行代码中)
        -> 语法:
            委托类型 委托变量 = delegate(参数) { 方法体 };
            int         num      = 1 + 2;

4、 Lambda表达式(匿名方法的一个衍生)
    -> 语法:
        (参数) => 执行体;
        // => 读作goes to
    -> 说明
        -> Lambda表达式是一个表达式(注意)
        -> ()中的参数,如果没有冲突,可以省略类型
        -> Lambda执行体,如果只有一句话,可以省略花括号
        -> 返回值的return可以省略
        -> Lambda表达式执行体中的变量可以引用到外面(*奇异*)
    -> Lambda表达式来源于函数式变成Lisp语言
        Erlang一个函数式编程语言
        函数式编程语言在并操作中应用非常广泛
        Lambda表达式树(晦涩的)
            () => 表达式1
                => 表达式2
                => 表达式3
                => 表达式4
                => 表达式5
=============================================
补充扩展: