Event事件和发布者/订阅者模式

2022/4/15 6:15:53

本文主要是介绍Event事件和发布者/订阅者模式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

很多程序都有这样的一个需求,当一个特定的事件发生时,程序的其他部分能够得到通知,并且需要做一些事情。这个时候就需要事件了。

发布者/订阅者模式

发布者/订阅者模式(publisher/subscriber pattern)就是满足这种需求,设计模式中也叫观察者模式。发布者存储一个方法集合,并且提供一个注册方法,让订阅者把自己的方法注册进去,这样在事件发生的时候,发布者可以调用注册到存储集合中的所有方法。

有以下要点:

  • 发布者(publisher)
  • 订阅者(subscriber)
  • 事件处理程序(event handler)订阅者注册到发布者的方法
  • 触发(raise)事件 当事件被调用(invoke)或触发(fire)时,所有注册的事件处理程序会被依次调用

使用步骤

  1. 声明委托类型
  2. 声明事件
  3. 事件处理程序声明
  4. 订阅事件/注册事件
  5. 触发事件(调用事件)

代码示例:

using EventDemo;

void Main()
{
    Publisher pub = new Publisher(); //发布者对象
    Subscriber sub = new Subscriber(); //订阅者对象
    pub.BtnPressEvent += sub.ProcBtnPress; //4、订阅事件(或者说给事件添加处理程序)
    pub.ButtonPress(); //5、触发事件
}

namespace EventDemo
{
    //1、声明委托类型
    delegate void DelButton(object sender, int id);

    //发布者类型
    class Publisher
    {
        //2、声明一个事件成员变量
        public event DelButton BtnPressEvent;

        //事件触发方法
        public void ButtonPress()
        {
            Button button1 = new Button();
            if (BtnPressEvent != null)
            {
                BtnPressEvent(button1, 10);
            }
        }
    }
	
    //订阅者类型
    class Subscriber
    {
        public void ProcBtnPress(object sender, int id)
        {
            Console.WriteLine($"Id of button is {id}");
        }
    }
}//namespace

1、声明委托类型

//1、声明委托类型
delegate void DelButton(object sender, int id);

事件的声明需要依赖此委托类型,并且事件处理程序的格式要与此委托保持一致。事件与委托很像,它包含了一个私有的内部委托。

  • 事件的委托是私有的,无法被直接访问
  • 事件提供的操作比委托少,一般只有添加、删除和调用事件处理程序
  • 事件触发时,它通过调用内部的委托,来依次调用存放在委托方法列表中的事件处理程序

2、声明事件变量

语法格式:

public event 委托类型 事件名称;

//2、声明一个事件成员变量,并且被隐式自动初始化为null
public event DelButton BtnPressEvent;

public static event DelButton BtnPressEvent; //声明为静态成员,局部于类

public event DelButton Event1, Event2, Event3; //同时声明多个事件

注意,事件是一个成员变量,而不是类型,它可以声明在类和结构中。这里使用public修饰后,外部的程序才可以向该事件注册处理程序。

BCL中有一个EventHandler的委托,专门用于系统事件。

3、事件处理程序

在订阅者类型中,定义了事件处理程序,该方法的格式必须保持和委托类型一致,要有相同的返回值和方法签名。该事件处理程序用于在事件触发时,被事件调用。最典型的就是响应winform或wpf中控件的事件,譬如像按钮按下、下拉框选择更改、文本框内容修改的事件等等。

//订阅者类型
class Subscriber
{
    //3、事件处理程序(按钮按下处理)
    public void ProcBtnPress(object sender, int id)
    {
        Console.WriteLine($"Id of button is {id}");
    }
}

4、订阅事件

有了事件处理程序后,就可以把我们添加的方法注册到事件上了,或者说订阅该事件。在示例中,我们把自定义的事件处理方法ProcBtnPress通过+=的方式,添加到事件中去,这和委托增加方法的方式一致。

这样一来,可以把多个订阅者对象的自定义方法添加到事件中,又叫做多个订阅者订阅了同一个发布者的事件。

void Main()
{
    Publisher pub = new Publisher(); //发布者对象
    Subscriber sub = new Subscriber(); //订阅者对象
    pub.BtnPressEvent += sub.ProcBtnPress; //4、订阅事件(或者说给事件添加处理程序)
    pub.ButtonPress(); //5、触发事件
}

5、事件触发

在示例中,我们在发布者类型中,写了一个事件触发的方法。事件触发其实就是在某个需要的地方,调用该事件,内部会依次执行委托中的方法。

//发布者类型
class Publisher
{
    //2、声明一个事件成员变量
    public event DelButton BtnPressEvent;

    //3、事件触发方法
    public void ButtonPress()
    {
        Button button1 = new Button();
        if (BtnPressEvent != null)
        {
            BtnPressEvent(button1, 10);
        }
    }
}

然后在外部调用事件触发方法。

void Main()
{
    Publisher pub = new Publisher(); //发布者对象
    Subscriber sub = new Subscriber(); //订阅者对象
    pub.BtnPressEvent += sub.ProcBtnPress; //4、订阅事件(或者说给事件添加处理程序)
    pub.ButtonPress(); //5、触发事件 
}

标准事件的使用

上面说到BCL中有一个EventHandler的委托,专门用于系统事件,它是.Net框架提供的标准模式。

//sender: 发起事件的对象的引用,类型是object可以兼容所有类型,但是使用的时候需要把object转成对应类型
//s: 触发事件传进来的参数基类引用
public delegate void EvnetHandler(object sender, EventArgs e);

第二个参数要注意, 类型EventArgs是参数基类类型, 并不能直接使用, 要传递参数必须要派生一个参数类继承自EventArgs用来传递参数。

EventArgs类的定义:

// System.EventArgs
using System;
using System.Runtime.CompilerServices;

[Serializable]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class EventArgs
{
    public static readonly EventArgs Empty = new EventArgs();
}

下面我们使用标准事件委托EventHandler和自定义参数类,来实现事件的使用

using EventDemo;

void Main()
{
    CustomButton btn = new CustomButton(); //发布者对象
    Subscriber sub = new Subscriber(); //订阅者对象
    btn.BtnPressEvent += sub.ProcBtnPress; //订阅事件
    btn.Click(); //事件触发
}

namespace EventDemo
{
    //发布者类, 这里写了一个简单的自定义按钮类作为发布者
    class CustomButton
    {
        //2、这里我们使用系统的标准事件委托来声明事件变量
        //这里的格式是使用了泛型委托,将默认的EventArgs参数类替换成我们自定义的
        public event EventHandler<CustomButtonEventArgs> BtnPressEvent;
        
        //自定义参数变量
        private CustomButtonEventArgs buttonEventArgs = new CustomButtonEventArgs();
        
        //3、事件触发方法
        public void Click()
        {
            buttonEventArgs.Id = 10;
            buttonEventArgs.Value = 255;
            
            if (BtnPressEvent != null)
            {
                BtnPressEvent(this, buttonEventArgs);
            }
        }
    }
    
    //订阅者类
    class Subscriber
    {
        //4、自定义事件处理程序(按钮按下处理)
        //注意,这里的参数要和标准委托EventHandler保持一致
        public void ProcBtnPress(object sender, EventArgs e)
        {
            Console.WriteLine($"The publisher Type is {sender.GetType().Name}");
            
            CustomButtonEventArgs ea = e as CustomButtonEventArgs;
            Console.WriteLine($"The eventArgs is {ea.Id} and {ea.Value}");
        }
    }
    
    //1、自定义按钮的参数类
    class CustomButtonEventArgs : EventArgs
    {
        //这里的参数可以存放一些外部的自定义数据
        public int Id { get; set; }
        public int Value { get; set; }
    }
	
}//namespace


这篇关于Event事件和发布者/订阅者模式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程