• 多播委托与事件


    多播委托与事件

    1.多播委托定义以及使用

    我们通过委托可以实现把方法作为参数,传递给委托执行。同样,我们的委托也可以依次执行多个方法,此时就需要我们的多播委托了。

    没有接触多播委托之前,我们调用多个方法的委托定义如下:

              ReturnWithPara para = new ReturnWithPara(ShowId); //当前类的方法
                    ReturnWithPara para1 = ShowId;//当前类的方法
                    ReturnWithPara para2 = (i, name) => Console.WriteLine("编号:" + i + ",名称:" + name);//lamda表达式
                    ReturnWithPara para3 = new OtherClass().ShowId;//外部类的实例方法
                    ReturnWithPara para4 = OtherClass.ShowIdStatic;//外部类的静态方法

    当使用多播委托后,我们的代码如下:

              //多播委托方式:通过+=添加方法,形成方法链,并按顺序执行
                    ReturnWithPara para = new ReturnWithPara(ShowId); //当前类的方法
                    para += ShowId;
                    para += (i, name) => Console.WriteLine("编号:" + i + ",名称:" + name);//lamda表达式
                    para += new OtherClass().ShowId;//外部类的实例方法
                    para += OtherClass.ShowIdStatic;//外部类的静态方法
                    para.Invoke(21, "张三");

    多播委托方式:通过+=添加方法,形成方法链,Invoke时按添加顺序执行方法.

    同样,我们也可以通过-=给委托实例移除方法,如下所示

                    //多播委托移除:通过-=给委托实例移除方法,从方法链的尾部开始匹配,遇到第一个完全吻合的移除,并且只移除一次
                    para -= ShowId;
                    para -= (i, name) => Console.WriteLine("编号:" + i + ",名称:" + name);//lamda表达式
                    para -= new OtherClass().ShowId;//外部类的实例方法
                    para -= OtherClass.ShowIdStatic;//外部类的静态方法
                    para.Invoke(22, "李四");

    注意:多播委托移除:通过-=给委托实例移除方法,从方法链的尾部开始匹配,遇到第一个完全吻合的移除,并且只移除一次

    以上代码执行后,我们会发现(i, name) => Console.WriteLine("编号:" + i + ",名称:" + name);和new OtherClass().ShowId;没有移除成功。

    这是因为:1.每个lamda表达式在编译时都会生成一个不同的方法,但都属于同一个实例。因此lamda表达式不能移除,所以不推荐lamda表达式写法

            2.new OtherClass().ShowId不能移除是因为是两个不同的匿名对象,所以不能移除

    多播委托不能直接调用异步方法(eg:para.BeginInvoke(22,"李四");),如果要使用异步调用,可以采取下面的方法

              ReturnWithPara para = new ReturnWithPara(ShowId); //当前类的方法
                    para += ShowId;
                    para += (i, name) => Console.WriteLine("编号:" + i + ",名称:" + name);//lamda表达式
                    para += new OtherClass().ShowId;//外部类的实例方法
                    para += OtherClass.ShowIdStatic;//外部类的静态方法
                    foreach (var item in para.GetInvocationList())
                    {
                        para.BeginInvoke(21, "张三", null, item);
                    }

    在上述代码中,我们通过para.GetInvocationList()方法获取所有的执行方法,循环执行每个的异步方法。

    注意:由于多播委托执行带返回值的多播委托时,只返回最后一个方法的返回值,所以多播委托不适用于带返回值的委托。

    多播委托常用的场景就是观察者模式。如下代码所示

    我们首先定义个Cat,Chicken等实体,每个实体都有一个方法事件。Cat的Miao方法会引起连锁反应,会引起鸡叫,baby哭泣等等,Cat类里面定义了个委托Cathander

     public class Cat
        {
            public void Miao()
            {
                Console.WriteLine("Miao····");
                if (Cathander != null)
                {
                    Cathander.Invoke();
                }
            }
            public Action Cathander;
    }

    在程序的上级调用中如下所示:

              Cat cat = new Cat();
                    cat.Cathander += new Chicken().Wo;
                    cat.Cathander += new Dog().Wang;
                    cat.Cathander += new Baby().Cry;
                    cat.Cathander += new Father().Roar;
                    cat.Cathander += new Brother().Turn;
                    cat.Cathander += new Mother().Run;
                    cat.Miao();
    cat.Miao()执行后就会调用绑定了事件的多播委托Cathander

     使用观察者设计模式的好处:保证了Cat类的稳定,需求变更时,只需修改最上层调用即可,无需关注cat代码

    2.事件

    定义:多播委托的定义前面加一个event关键字,如下所示,我们子啊Cat里面定义了一个事件CathanderEvent

    public event Action CathanderEvent;
            public void MiaoEvent()
            {
                Console.WriteLine("Miao····");
                if (CathanderEvent != null)
                {
                    CathanderEvent.Invoke();
                }
            }

    上层代买调用执行:

              Cat cat = new Cat();
                    cat.CathanderEvent += new Chicken().Wo;
                    cat.CathanderEvent += new Dog().Wang;
                    cat.CathanderEvent += new Baby().Cry;
                    cat.CathanderEvent += new Father().Roar;
                    cat.CathanderEvent += new Brother().Turn;
                    cat.CathanderEvent += new Mother().Run;
                    cat.MiaoEvent();

    观察以上代码,和多播委托很类似。

    3.多播委托与事件的区别和联系

    从以上部分介绍,我们是否感觉多播委托和事件很类似,那为什么还要用事件呢?

    事件加了权限限制,在事件定义的外部类(或定义类的子类)中,只允许外部+=和-=。不能进行类似cat.CathanderEvent=null之类的赋值,这种赋值只能在定义事件的内部类中才可以。

    委托与事件的区别和联系:委托是一个类,而事件是委托的一个实体对象

    4.事件的运用场景

     事件应用很广泛,主要包含:

    1.服务器的控件的点击事件、下拉事件等。

    2、Webform页面声明周期,各种页面级事件(pre_init、page_load、application_start)。

    3.请求级事件:经常注册module 等等

  • 相关阅读:
    TCP和UDP区别
    session和cookie的区别
    2019 腾讯正式批笔试题题解
    modCount干嘛的
    分布式系统唯一ID生成方案汇总
    分布式数据库名词
    快手第一题
    南柯一梦
    349. 两个数组的交集
    synchronized锁优化
  • 原文地址:https://www.cnblogs.com/zxwDont/p/11655438.html
Copyright © 2020-2023  润新知