• C#事件


      事件基于委托,为委托提供了一种发布/订阅机制。如Windows应用程序中,Button类提供的Click事件就是委托。

    1、普通事件(强事件)

      在编写事件的过程中,需要构造一个事件参数类,用以存放事件的数据。其次,需要一个事件发布者和侦听者。当事件发布者发布事件时,侦听者将接受到消息。事件参数类继承自EventArgs类。在事件发布者类中申明事件,并通过侦听者进行侦听。其中CarInfoEventArgs是事件发布类,CarDealer是事件发布者,Consumer是事件侦听者。

    //所有侦听器都可以使用该参数
    class CarInfoEventArgs : EventArgs
    {
        public string Car { get; private set; }
        public CarInfoEventArgs(string car)
        {
            Car = car;
        }
    }
    // 事件发布者
    class CarDealer
    {
        //事件发布者的事件参数
        public event EventHandler<CarInfoEventArgs> NewCarInfo;
        public void NewCar(string car)
        {
            Console.WriteLine("CarDealer, new car {0}", car);
            RaiseNewCarInfo(car);
        }
        //事件执行方法,委托对象定义和事件发生回调调用的地方。
        protected virtual void RaiseNewCarInfo(string car)
        {
            if (NewCarInfo != null)
            {
                NewCarInfo(this, new CarInfoEventArgs(car));
            }
        }
    }
    //顾客(侦听器)调用了发布者事件的参数,提供委托(函数指针)实例给委托(函数指针)对象
    class Consumer
    {
        private string name;
    
        public Consumer(string name)
        {
            this.name = name;
        }
    
        public void NewCarIsHere(object sender, CarInfoEventArgs e)
        {
            Console.WriteLine("{0}: Car {1} is new", name, e.Car);
        }
    }

      在Main函数中调用:

    class Program
    {
        static void Main(string[] args)
        {
            //事件发布者
            CarDealer dealer = new CarDealer();
    
            var michael = new Consumer("Michael");
            // 将委托实例赋值给了委托对象  
            dealer.NewCarInfo += michael.NewCarIsHere;
            // 事件发生,发布者调用委托对象,发布给订阅者  
            dealer.NewCar("Mercedes");
            var nick = new Consumer("Nick");
            // 增加订阅者  
            dealer.NewCarInfo += nick.NewCarIsHere;
    
            // 发布者多播给多个订阅者  
            dealer.NewCar("Ferrari");
            // 减少订阅者,如但是发布者会仍然有一个引用而无法垃圾回收订阅者资源,需要一个弱引用管理器来管理。  
            dealer.NewCarInfo -= michael.NewCarIsHere;
            // 发布者发布给订阅者  
            dealer.NewCar("Toyota");
        }
    }

      在该种方法中,所有的事件都是强引用,当不在使用某个订阅者时,其不会释放内存。因为在委托中引用了改对象的信息。

    2、弱事件

      弱事件需要实现弱事件类WeakCarInfoEventManager,它继承自WindowsBase命名空间System.Windows下的WeakEventManager。弱事件模式,发布程序和侦听程序不再强连接,当不再引用侦听器后,它就会被垃圾回收。其具体实现如下:

    // 弱事件管理器
    class WeakCarInfoEventManager : WeakEventManager
    {
        //需要实现为单例模式,以确保唯一管理者
        public static WeakCarInfoEventManager CurrentManager
        {
            get
            {
                var manager =GetCurrentManager(typeof(WeakCarInfoEventManager)) as WeakCarInfoEventManager;
                if (manager == null)
                {
                    manager = new WeakCarInfoEventManager();
    
                    SetCurrentManager(typeof(WeakCarInfoEventManager), manager);
                }
                return manager;
            }
        }
        //侦听器使用这些方法连接发布程序,此处添加侦听器
        public static void AddListener(object source, IWeakEventListener listener)
        {
            CurrentManager.ProtectedAddListener(source, listener);
        }
        //侦听器使用这个方法断开与发布程序的连接,此处删除侦听器
        public static void RemoveListener(object source, IWeakEventListener listener)
        {
            CurrentManager.ProtectedRemoveListener(source, listener);
        }
        // 开始侦听管理事件(订阅一个方法)
        protected override void StartListening(object source)
        {
            (source as CarDealer).NewCarInfo += CarDealer_NewCarInfo;
        }
        // 停止侦听管理事件(取消订阅一个方法)
        protected override void StopListening(object source)
        {
            (source as CarDealer).NewCarInfo -= CarDealer_NewCarInfo;
        }
    
        void CarDealer_NewCarInfo(object sender, CarInfoEventArgs e)
        {
            DeliverEvent(sender, e);//在侦听器中调用IWeakEventListener接口的ReceviceWeakEnvent()方法,所以侦听器需要实现接口
        }
    }

      顾客(侦听器)需要改为实现IWeakEventListener接口的ReceiveWeakEvent方法。触发事件时,从弱事件管理器中调用该方法。

    class Consumer :IWeakEventListener
    {
        private string name;
    
        public Consumer(string name)
        {
            this.name = name;
        }
    
        public void NewCarIsHere(object sender, CarInfoEventArgs e)
        {
            Console.WriteLine("{0}: Car {1} is new", name, e.Car);
        }
    
        //弱事件的使用还需要让阵痛期实现接口IWakeEventListener。在Consumer类中增加一个函数……
        bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            NewCarIsHere(sender, e as CarInfoEventArgs);
            return true;
        }
    }

      在Main函数中调用为:

    static void Main(string[] args)
    {
        CarDealer dealer = new CarDealer();
    
        var michael = new Consumer("Michael");
        //使用弱事件管理器
        WeakCarInfoEventManager.AddListener(dealer, michael);
    
        dealer.NewCar("Ferrari");
    
        var nick = new Consumer("Sebastian");
        WeakCarInfoEventManager.AddListener(dealer, nick);
    
        dealer.NewCar("Mercedes");
    
        WeakCarInfoEventManager.RemoveListener(dealer,  michael);
        //此时,michael侦听器已不再引用,可垃圾回收
    
        dealer.NewCar("Red Bull Racing");
    }

    3、泛型弱事件管理器

      泛型弱事件管理器简化了弱事件的实现。将以上代码改为泛型弱事件,事件源时CarDealer类型,事件参数为CarInfoEventArgs类型。WeakEventManager类定义了AddHandler方法订阅事件,RemoveHandler方法取消事件。实现代码如下:

    static void Main(string[] args)
    {
        //事件发布者
        CarDealer dealer = new CarDealer();
    
        var michael = new Consumer("Michael");
        WeakEventManager<CarDealer, CarInfoEventArgs>.AddHandler(dealer, "NewCarInfo", michael.NewCarIsHere);
    
        dealer.NewCar("Mercedes");
    
        var nick = new Consumer("Nick");
        WeakEventManager<CarDealer, CarInfoEventArgs>.AddHandler(dealer, "NewCarInfo", nick.NewCarIsHere);
        
        dealer.NewCar("Ferrari");
        WeakEventManager<CarDealer, CarInfoEventArgs>.RemoveHandler(dealer, "NewCarInfo", michael.NewCarIsHere);
    
        dealer.NewCar("Toyota");
    }
  • 相关阅读:
    MySQL(一)序
    Mockito 小结
    如何入门一个开源软件
    面经
    琐碎的想法(四)键盘布局、快捷键的由来
    琐碎的想法(二)网络协议——人们给计算机的一组“约定”
    Java源码赏析(六)Class<T> 类
    Java随谈(五)Java常见的语法糖
    Java随谈(四)JDK对并发的支持
    Event Loop和宏任务微任务
  • 原文地址:https://www.cnblogs.com/pilgrim/p/9231302.html
Copyright © 2020-2023  润新知