zoukankan      html  css  js  c++  java
  • 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();
    
            }
        }
    }

    截图如下:

     

  • 相关阅读:
    【LeetCode OJ】Remove Element
    【LeetCode OJ】Remove Duplicates from Sorted Array
    【LeetCode OJ】Swap Nodes in Pairs
    【LeetCode OJ】Merge Two Sorted Lists
    【LeetCode OJ】Remove Nth Node From End of List
    【LeetCode OJ】Two Sum
    【LeetCode OJ】Majority Element
    最长公共子序列问题
    php fopen与file_get_contents的区别
    PHP 技巧集合
  • 原文地址:https://www.cnblogs.com/MoRanQianXiao/p/7773911.html
Copyright © 2011-2022 走看看