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();

        }
    }
}

截图如下:

 

posted @ 2017-11-03 10:42  丢了蜡笔小新会哭〆  阅读(259)  评论(0编辑  收藏  举报