• c#之事件


    事件

    前言:事件基于委托,为委托提供了一种发布/订阅的机制。在架构的内部到处都能看到事件。在Windows应用程序中,Button类提供了Click事件。这类事件就是委托。触发Click事件时调用的处理程序方法需要定义,其中参数由委托类型定义。


    在本次的实例中。事件用于连接CarDealer(汽车代理商)类和Consumer(顾客类)类。CarDealer类提供了一个新车到达时发出的事件,Consumer类订阅了该事件,已获得新车到达的通知。

    一:事件发布程序:

    从CarDealer类开始,它基于事件提供一个订阅,CarDealer类用Event关键字定义了类型为EventHandler<CarInfoEventArgs>的NewCarInfo事件。在NewCar()方法中,通过调用RaiseNewCarInfo方法调用NewCarInfo事件。这个方法的实现检查委托是否为空。如果不为空,就引发事件。完整的代码如下:

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace _17事件
    {
        /// <summary>
        /// 新车类
        /// </summary>
        public class CarInfoEventArgs : EventArgs
        {
    
            public string Car { get; private set; }
    
            /// <summary>
            /// 构造函数的定义
            /// </summary>
            /// <param name="car"></param>
            public CarInfoEventArgs(string car)
            {
                this.Car = car;
            }
    
        }
    }

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace _17事件
    {
        /// <summary>
        /// 新车达到时触发的事件
        /// </summary>
        public class CarDealer
        {
            //事件的定义
            public event EventHandler<CarInfoEventArgs> NewCarInfo;
    
            /// <summary>
            /// 新车到达
            /// </summary>
            /// <param name="car">新车的名字</param>
            public void NewCar(string car)
            {
                Console.WriteLine("CarDealer,new car{0}", car);
                //如果不为空就引发事件
                RaiseNewCarInfo(car);
            }
    
            /// <summary>
            /// 事件的引发
            /// </summary>
            /// <param name="car">新车</param>
            protected virtual void RaiseNewCarInfo(string car)
            {
                //事件的调用
                NewCarInfo?.Invoke(this, new CarInfoEventArgs(car));
    
                //EventHandler<CarInfoEventArgs> newCarInfo = NewCarInfo;
                //if (newCarInfo != null)
                //{
                //    newCarInfo(this, new CarInfoEventArgs(car));
                //}
            }
    
        }
    }

    CarDealer类提供了EventHandler<CarInfoEventArgs>的NewCarInfo事件。作为一个约定,事件一般使用带两个参数的方法,其中一个第一个参数是一个对象,包含事件的发送者,第二个参数提供了事件的相关的信息。   第二个参数岁随不同的事件类型而不同。有了泛型委托EventHandler<T>,这就不再需要委托了。EventHandler<TEventArgs>定义了一个处理程序,它返回void,接收两个参数。第一个参数的类型必须是object类型,第二个参数是T类型。EventHandler<TEventArgs>还定义了一个关于T的约束:它必须派生自基类EventArgs,CarInfoEventArgs就派生自基类EventArgs。

    CarDealer类在RaiseNewCarInfo方法中触发事件。使用委托NewCarInfo和花括号可以调用给事件订阅的所有处理程序。注意和多播委托一样,方法的调用顺序无法保证。为了更多的控制处理程序的调用,可以使用Delegate类的GetInvocationList()方法,访问委托列表中的每一项,并独立的调用每个方法。

    在触发事件之前,需要检查委托NewCarInfo是否为空。如果没有订阅处理程序,委托就是空,代码如下:

            /// <summary>
            /// 事件的引发
            /// </summary>
            /// <param name="car">新车</param>
            protected virtual void RaiseNewCarInfo(string car)
            {
                //事件的调用
                NewCarInfo?.Invoke(this, new CarInfoEventArgs(car));
    
                //EventHandler<CarInfoEventArgs> newCarInfo = NewCarInfo;
                //if (newCarInfo != null)
                //{
                //    newCarInfo(this, new CarInfoEventArgs(car));
                //}
            }

    二:事件的监听器:

    Consumer类用作事件的监听器。这个类订阅了CarDealer类的事件,并定义了NewCarIsHere方法,该方法满足于EventHandler<CarInfoEventArgs>委托的要求,其参数就是object和CarInfoEventArgs类型。完整的代码实现如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace _17事件
    {
        /// <summary>
        /// 订阅该事件,以获得新车到达的通知
        /// </summary>
        public class Consumer
        {
            private string _name;
            public string Name
            {
                get { return _name; }
                set { _name = value; }
            }
    
            /// <summary>
            /// 进行初始化赋值
            /// </summary>
            /// <param name="name"></param>
            public Consumer(string name)
            {
                this.Name = name;
            }
    
            /// <summary>
            /// 事件的订阅
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            public void NewCarIsHere(object sender, CarInfoEventArgs e)
            {
                Console.WriteLine("{0}: car {1} is new", this.Name, e.Car);
            }
        }
    }

    现在需要连接事件发布程序和订阅器了。为此使用CarDealer类的NewCarInfo事件,通过“+=”来创建一个订阅。消费者michael(变量)订阅了事件,接着sebastian也订阅了该事件,然后michael通过“-=”取消了订阅。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace _17事件
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                //创建一个汽车代理商
                CarDealer dealer = new CarDealer();
    
                //顾客:迈克尔
                Consumer michael = new Consumer("迈克尔");
                //迈克尔订阅了事件
                dealer.NewCarInfo += michael.NewCarIsHere;
    
                //顾客:塞巴斯蒂安
                Consumer sebastian = new Consumer("塞巴斯蒂安");
                //塞巴斯蒂安订阅了事件
                dealer.NewCarInfo += sebastian.NewCarIsHere;
    
    
                //新车来了:法拉利
                dealer.NewCar("法拉利");
    
                //新车来了:梅塞德斯牌汽车
                dealer.NewCar("梅塞德斯牌汽车");
    
                //顾客(迈克尔)取消了事件的订阅
                //dealer.NewCarInfo -= michael.NewCarIsHere;
    
                //新车来了:红牛车队
                dealer.NewCar("红牛车队");
    
                //新车来了:奥迪
                //dealer.NewCar("奥迪");
    
                Console.ReadKey();
    
            }
        }
    }

    截图如下:

     

  • 相关阅读:
    多线程锁--怎么理解Condition
    ThreadPoolExecutor
    ThreadFactory
    java内部类的初始化
    Android Private Libraries 和 Dependencies的区别
    Android严苛模式StrictMode使用详解
    [法律法规]《网络安全等级保护条例(征求意见稿)》
    [法律法规]中华人民共和国网络安全法
    Sqlserver tablediff的简单使用
    Sqlserver 命令行方式修改 用户密码的方法
  • 原文地址:https://www.cnblogs.com/MoRanQianXiao/p/7773911.html
Copyright © 2020-2023  润新知