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");
}

猜你喜欢

转载自www.cnblogs.com/pilgrim/p/9231302.html