C#学习笔记之——事件

下面列举示例对事件的概念和基本用法进行说明(例子来自陈广老师的课堂,自己稍作了修改和融合)

为了省去创建GUI那些繁琐的步骤,更清晰地逼近事件的本质,接下来的所有程序都是控制台程序,程序最后的Console.ReadKey()是为了使程序中途停下来,以便看清楚执行过程中的输出。

using System;

/*
 * 事件是类在发生其关注的事情时用来提供通知的一种方式。
 * 例如:封装用户界面控件的类可以定义一个在用户单击该控件时发生的事件,控件类不关心单击按钮时发生了什么,
 * 但它需要告知派生类单击事件已发生,然后,派生类可选择如何响应。
 */

/*
 * 事件发行者(Publisher)
 * 一个事件发行者,也称作发送者(Sender),其实就是一个对象,这个对象会自行维护本身的状态信息。
 * 当本身状态信息变动时,便触发一个事件,并通知所有的事件订阅者。
 */

/*
 * 事件订阅者(Subscriber)
 * 对事件感兴趣的对象,也称为接受者(Receiver),可以注册感兴趣的事件,通常需提供一个事件处理程序,
 * 在事件发行者触发一个事件后,会自动执行这段代码的内容。
 */

/*
 * 事件的四个步骤:
 * 1.在事件发行者中定义一个事件
 * 2.在事件发行者中触发事件
 * 3.在事件订阅者中定义事件处理程序
 * 4.向事件发行者订阅一个事件
 */

/// <summary>
/// 出版社(事件发行者)
/// </summary>
class Publisher
{
    public delegate void publish();//声明事件 所需的委托

    /// <summary>
    /// 事件的声明(1.在事件发行者中定义一个事件)
    /// </summary>
    public event publish onPublish;//如果去掉关键字event,实际上就是声明了一个委托变量

    /// <summary>
    /// 触发事件的方法(2.在事件发行者中触发事件)
    /// </summary>
    public void Issue()
    {
        Console.WriteLine("出版社发行刊物");
        if (onPublish != null)
        {
            onPublish();//触发事件
        }
    }
}

/// <summary>
/// 订阅者(事件订阅者)
/// </summary>
class Subscriber
{
    /// <summary>
    /// (3.在事件订阅者中定义事件处理程序)
    /// </summary>
    public void Receive()//该方法必须与事件发行者中委托的 返回类型 和 参数 一致
    {
        Console.WriteLine("订阅者收到刊物");
    }
}

/// <summary>
/// 演艺出版社和订阅者之间的故事
/// </summary>
class Story
{
    static void Main()
    {
        Publisher pub = new Publisher();//创建一个发行者pub
        Subscriber zs = new Subscriber();//创建一个订阅者张三zs
        pub.onPublish += new Publisher.publish(zs.Receive);//(4.向事件发行者订阅一个事件)
        pub.Issue();//触发事件(发行者发型刊物,这时会触发订阅者收到刊物事件)
        Console.ReadKey();
    }
}

执行结果 

 

下面示例是上面示例的增强,同时“()”中标示了.NET Framework事件设计准则

using System;

/// <summary>
/// 出版事件数据类(说明:提供事件数据的类;对类以EventNameEventArgs进行命名;从System.EventArgs继承该类)
/// </summary>
class PubEventArgs : EventArgs
{
    private readonly string magazineName;//杂志名称,readonly表示赋值后只读
    private readonly DateTime pubDate;//出版日期

    public string MagazineName
    {
        get { return this.magazineName; }
    }
    public DateTime PubDate
    {
        get { return this.pubDate; }
    }

    public PubEventArgs(string magazineName, DateTime pubDate)//构造函数
    {
        this.magazineName = magazineName;
        this.pubDate = pubDate;
    }    
}

class Publisher
{
    /// <summary>
    /// 声明出版电脑杂志事件所需的委托(说明:声明委托使用void作为返回值;EventName事件对应的事件委托是EventNameEventHandler;
    /// 事件接受两个传入参数,一律命名为sender和e
    /// 如果事件不需要传递任何数据,也要声明两参数,e参数可以直接使用系统提供的System.EventArgs类;
    /// 如果需要传递数据,则要从System.EventArgs继承一个类,并吧数据放在里面)
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void PubComputerEventHandler(object sender, PubEventArgs e);

    public delegate void PubLifeEventHandler(object sender, PubEventArgs e);//声明出版生活杂志事件所需的委托

    public event PubComputerEventHandler PubComputer;//出版电脑杂志的事件声明

    public event PubLifeEventHandler PubLife;//出版生活杂志的事件声明

    /// <summary>
    /// 出版电脑杂志受保护方法(说明:在引发事件的类中提供一个受保护的方法,以OnEventName进行命名,在该方法中引发该事件)
    /// </summary>
    /// <param name="e"></param>
    protected virtual void OnPubComputer(PubEventArgs e)
    {
        PubComputerEventHandler handler = PubComputer;//声明临时变量handler,是为了防止线程同步问题
        if (handler != null)
        {
            handler(this, e);//触发事件
        }
    }

    protected virtual void OnPubLife(PubEventArgs e)//出版生活杂志受保护方法
    {
        PubLifeEventHandler handler = PubLife;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    public void IssueComputer(string magazineName, DateTime pubDate)//出版电脑杂志方法
    {
        Console.WriteLine("发行" + magazineName);
        OnPubComputer(new PubEventArgs(magazineName, pubDate));//调用出版电脑杂志受保护方法
    }

    public void IssueLife(string magazineName, DateTime pubDate)//出版生活杂志方法
    {
        Console.WriteLine("发行" + magazineName);
        OnPubLife(new PubEventArgs(magazineName, pubDate));
    }
}

class Subscriber
{
    private string name;
    public Subscriber(string name)
    {
        this.name = name;
    }
    public void Receive(object sender, PubEventArgs e)//订阅者收到杂志方法,在出版社出版该杂志时触发该方法
    {
        Console.WriteLine(e.PubDate + " " + name + "收到" + e.MagazineName);
    }
}

class Story
{
    static void Main()
    {
        Publisher pub = new Publisher();//创建出版社
        Subscriber zs = new Subscriber("张三");//创建订阅者张三
        pub.PubComputer += new Publisher.PubComputerEventHandler(zs.Receive);//张三向杂志社订阅电脑杂志
        Subscriber ls = new Subscriber("李四");//创建订阅者李四
        pub.PubComputer += new Publisher.PubComputerEventHandler(ls.Receive);//李四向杂志社订阅电脑杂志
        pub.PubLife += new Publisher.PubLifeEventHandler(ls.Receive);//李四向杂志社订阅生活杂志
        pub.IssueComputer("电脑杂志", Convert.ToDateTime("2006-01-01"));//出版社出版电脑杂志
        pub.IssueLife("生活杂志", Convert.ToDateTime("2006-01-01"));//出版社出版生活杂志
        Console.WriteLine();
        Console.WriteLine("一年以后");
        pub.PubComputer -= new Publisher.PubComputerEventHandler(ls.Receive);//李四退订电脑杂志
        pub.IssueComputer("电脑杂志", Convert.ToDateTime("2007-01-01"));//出版社出版电脑杂志
        pub.IssueLife("电脑杂志", Convert.ToDateTime("2007-01-01"));//出版社出版生活杂志
        Console.ReadKey();
    }
}

执行结果

 

posted on 2012-09-02 17:03  DeltaCat  阅读(328)  评论(0)    收藏  举报