zoukankan      html  css  js  c++  java
  • C#高级编程之事件

    在介绍事件之前,我们先讲解委托,然后由委托衍生讲解事件。

    现有这样的需求:要求在猫叫之后,执行狗哭,老鼠跑,孩纸哭的动作。

    初步的实现如下:

        class Program
        {
            static void Main(string[] args)
            {
                Cat cat = new Cat();
                cat.Miao();
            }
        }
    public void DogSaying()
            {
                Console.WriteLine("the dog is  barking");
            }
    public void BabyCry()
            {
                Console.WriteLine("the baby is crying");
            }
    public void MouseRunning()
            {
                Console.WriteLine("the mouse is running");
            }
            public void Miao()
            {
                Console.WriteLine("cat miaoing");
                new Dog().DogSaying();
                new Mouse().MouseRunning();
                new Baby().BabyCry();
            }

    执行这个方法后,我们会发现这个Miao叫方法依赖的类型太多了,依赖于Dog、Mouse、Baby类。如果任何一个环节发生改变,这个方法就要修改,导致这个方法非常不稳定。其实也不应该这样,猫应该就只是执行Miao一下的功能,单一职责。

    此时可以采用多播委托的方式:

    基于多播委托的观察者模式

    客户端添加如下代码:

                Console.WriteLine("*************多播委托************");
                cat.CatMiaoAction += new Dog().DogSaying;
                cat.CatMiaoAction += new Baby().BabyCry;
                cat.CatMiaoAction += new Mouse().MouseRunning;
                cat.MiaoDelegate();

    Cat类中添加如下代码:

        public void Miao()
            {
                Console.WriteLine("cat miaoing");
                MiaoDelegate();
            }
            public Action CatMiaoAction;
            /// <summary>
            /// 基于委托的观察者模式(C#)
            /// 把需要执行的动作放到委托中去
            /// </summary>
            public void MiaoDelegate()
            {
                Console.WriteLine($"{this.GetType().Name} Miao");//固定动作
                CatMiaoAction?.Invoke();
            }

    基于抽象接口的观察者模式

    定义一个IObject接口,这些动物都要实现接口中的void DoAction();方法。

    namespace DelegateObserverDemo
    {
        class Baby: IObject
        {
            public void BabyCry()
            {
                Console.WriteLine("the baby is crying");
            }
    
            public void DoAction()
            {
                this.BabyCry();
            }
        }
    }
    namespace DelegateObserverDemo
    {
        class Dog:IObject
        {
            public void DoAction()
            {
                this.DogSaying();
            }
    
            public void DogSaying()
            {
                Console.WriteLine("the dog is  barking");
            }
        }
    }

    客户端代码如下:

        static void Main(string[] args)
            {
                Cat cat = new Cat();
    
    
                Console.WriteLine("*************观察者模式*************");
                cat.AddObserver(new Dog());
                cat.AddObserver(new Baby() );
                cat.AddObserver(new Mouse());
                cat.MiaoAbserver();
    }

    Cat类代码:

        /// <summary>
            /// 基于面向抽象的观察者模式
            /// </summary>
            private List<IObject> _Observer = new List<IObject>();
            public void AddObserver(IObject observer)
            {
                _Observer.Add(observer);
            }
            public void MiaoAbserver()
            {
                Console.WriteLine($"{this.GetType().Name} Miao");
                foreach (var item in _Observer)
                {
                    item.DoAction();
                }
            }

    对比cat.AddObserver(new Dog())与委托中+=功能,可以发现两者还是有很多相同的地方。

    那能否通过事件来实现相同的功能呢?答案是可以的。

    委托与事件的区别

    委托实例.Invoke(参数列表)执行委托绑定的方法

    Cat中代码如下:

            //事件Event:就是一个委托的实例,加了一个Event关键字
            //事件实现了上面的需求
            //event:可以限定权限
            public event Action CatMiaoActionHandler;
            /// <summary>
            /// 基于委托的观察者模式(C#)
            /// 把需要执行的动作放到委托中去
    ///通过委托实例(亦即事件).Invoke(参数列表)触发委托
    /// </summary> public void MiaoEvent() { Console.WriteLine($"{this.GetType().Name} MiaoEvent");//固定动作 CatMiaoActionHandler?.Invoke(); Console.WriteLine($"{this.GetType().Name} aaa");//固定动作 Console.WriteLine($"{this.GetType().Name} bbb");//固定动作 }

    此处只是对CatMiaoAction加了个event关键字,取了个名字CatMiaoActionHandler;同时修改原来的MiaoDelegate函数名为MiaoEvent。

    C#声明委托:

        public delegate void Action();
    public event Action CatMiaoActionHandler;委托Action是一个类型(类比string,int,那此处就是public event string CatMiaoActionHandler),

    所以:[此处事件CatMiaoActionHandler是委托Action类型的一个实例,并用event关键字描述其为一个事件]

    客户端如下:

               Console.WriteLine("*************事件Event************");
                cat.CatMiaoActionHandler += new Dog().DogSaying;
                cat.CatMiaoActionHandler += new Baby().BabyCry;
                cat.CatMiaoActionHandler += new Mouse().MouseRunning;
                cat.MiaoEvent();

    可以看到与客户端执行委托相关方法没什么区别。但是上面委托的实现中我们在客户端可以对CatMiaoAction进行相关操作。

    cat.CatMiaoAction = null;

    cat.CatMiaoAction.Invoke();

    但是执行cat.CatMiaoActionHandler = null;就会报错

    可以看到event是限定了权限的,其只能在事件所在类的内部invoke;在外面是不行的,包括子类也不行。

        class ChildCat : Cat
        {
            public void Show()
            {
                //this.CatMiaoActionHandler = null;这句也会报错,故在子类中修改、操作也不行。
            }
        }

    委托实例【事件】(参数列表)执行委托绑定的方法

    除了上面的方式触发委托外,还有通过委托实例(参数列表)【即事件名(参数列表)】的方式调用触发委托,如下:

    客户端代码:

    Console.WriteLine("*************事件Event,通过委托实例(参数列表)【即事件名(参数列表)】的方式调用************");
                cat.CatMiaoActionHandler += new Dog().DogSaying;
                cat.CatMiaoActionHandler += new Baby().BabyCry;
                cat.CatMiaoActionHandler += new Mouse().MouseRunning;
                cat.MiaoEventAnotherMethod();
        ///通过委托实例(参数列表)【即事件名(参数列表)】的方式调用触发委托
            public void MiaoEventAnotherMethod()
            {
                Console.WriteLine($"{this.GetType().Name} MiaoEvent");//固定动作
                CatMiaoActionHandler();
                Console.WriteLine($"{this.GetType().Name} aaa");//固定动作
                Console.WriteLine($"{this.GetType().Name} bbb");//固定动作
            }

     联想到winForm中我们看到的各种事件,好像还差那么点意思。。别急。请看下面:

    内置的EventHandler委托如下,该委托包含两个参数sender,e分别:

        // 摘要:
        //     表示将用于处理不具有事件数据的事件的方法。
        //
        // 参数:
        //   sender:
        //     事件源。
        //
        //   e:
        //     不包含事件数据的对象。
        [ComVisible(true)]
        public delegate void EventHandler(object sender, EventArgs e);

    与其相关Click事件,其为EventHandler委托的实例:

    public event EventHandler Click;

    现在用该委托的实例 MyEvent 执行其绑定的方法

    public class Example
        {
            public event EventHandler myEvent;
            internal void Go()
            {
                object sender = 10;
                EventArgs e = new EventArgs();
                //为事件注册多个委托
                myEvent += Print;
                myEvent += Say;
                myEvent(sender, e);
            }
            void Print(object sender, EventArgs e)
            {
                Console.WriteLine(sender);
            }
            void Say(object sender, EventArgs e)
            {
                Console.WriteLine(sender);
            }
        }

    总结

    委托是一个类,是MultiCastDelegate基类的子类。

    事件是委托的一个实例;事件比委托更加安全,其只能在声明当前该事件的类的内部进行触发(不管是Invoke发方式还是委托实例【事件】(参数列表)执行委托绑定的方法),即使在子类也不行。

     
  • 相关阅读:
    Linux 下判断磁盘是ssd还是hdd
    Ceph rgw COR测试
    nfs 挂载选项
    【Linux命令】dmsetup--device mapper 管理工具(更底层的管理工具)
    Device Mapper 存储介绍
    easyui combotree 默认 初始化时就选中
    EasyUI 添加tab页(iframe方式)(转)
    EasyUI DataGrid 配置参数
    EasyUI 后台接受DataGrid传来的参数
    (转)combogrid的代码实例
  • 原文地址:https://www.cnblogs.com/shuzhongke/p/14025345.html
Copyright © 2011-2022 走看看