每天,我们的身边都在发生各种各样的新闻和事件,有让人不快的事件:跟女朋友分手了,国足又输了,飞机失事了,海地地震了……也有幸运的事件:考试拿了个高分,申雪赵宏博拿到冠军了……等等,可是,究竟什么是事件?或许是由于这个概念太普通了,以至于我常常忽略了它的存在,一直未能深究其义。而这个概念,是基于消息的程序设计和编写的基础和核心概念。C#接触也有一段时间了,一直没真正理解事件这个概念,在网上搜也没搜到相应的文章,一直就是一知半解的状态,然后就放到了一边,没去管它,还是自己基础太差,对Windows程序的消息机制完全没弄清楚,实为悲哀。近期做一个C#的项目,这回才对基于事件的程序设计有了一个自己的理解,把它写出来,算是一个总结吧,也希望各位看官批评指正。本文仅讨论基于C#语言层面的事件理解,不探讨底层消息机制。

1.什么是事件?

这个问题曾经让我十分困扰,在《C#高级编程第6版》中,对事件是这样说的:事件表示C#中已定义的一个对象,即处理通知过程的对象。可是这样说未免抽象,对于像我这样的初学者往往还是难以理解。而我的理解是,事件是处理事件的对象感兴趣的,能够感知或捕获到一种事物状态的改变。说白了,事件即改变。哲学上说,事物的运动是永恒的,静止是相对的。永恒的运动意味着事物本身在发生着改变,所以无时无刻,我们生活的这个世界和宇宙都有无穷的改变在发生,但是,这当中的绝大多数对你来说并不是事件,秘鲁总统死了,对秘鲁全国所有的人来说或许是一个事件,因为他们关心,可是对课堂正在听课全然不知的你来说就不是,除非你听到了这样一个新闻,开始关注,那么这个变化对你来说就是一个事件。所以,在这所有的变化中,你能捕获到的,感兴趣的变化,对你来说,就是一个事件。

那么,把事件这个概念放到程序设计中,又是怎样的呢?其实是一样的。同样的道理,只要机器开着,里面的硬件和软件就会发生状态的改变。可是对你要编写的代码来讲,并不是所有的这些改变都是事件。你所需要的事件,只是你对这些变化中感兴趣的极小一部分。你只需要找到你感兴趣的这样一种状态的改变,并且能够捕获它,就可以利用事件处理模型来完成你想做的事情了。

2.什么时候发出事件?

事件是发出的,它通知观察者,你感兴趣的状态变化已经产生了,赶快来处理。观察者捕获到这样一种变化,进行相应的处理。所以,在发生观察者感兴趣的状态变化时,就发出事件。而这,在C#中是通过执行委托实现的。在C#中,观察者就是事件处理代码。

3.如何发出和处理事件?

在C#中,发出事件通过执行委托。委托实际可以理解为指向函数指针队列的一个指针实例。这个概念可能有点绕,也就是说,每一个事件都有一个队列,上面挂满了指向函数的指针(当然这个队列有可能为空),而事件就是指向这个队列的指针。执行委托的时候,系统找到事件,然后找到它指向的函数指针队列,一一执行这个队列上各个指针指向的函数。而注册事件处理函数也就是将事件处理函数的指针挂上这个队列。排除底层实现,这是我个人的一点理解,请指正。

4.如何自定义事件?

我们都知道事件是一个实例,它会有它的类型,所以定义事件的时候,我们想到的第一个问题:定义一个实例,我们需要一个类型,那么事件的类型是什么?

在C#中,我们知道事件是一种委托类型,那么我们需要先定义一种委托类型:

delegate void EventHandler(object sender, EventArgs e);

这是一种非常奇怪的语法,但你要知道定义委托就是这么定义的,三个要素:返回类型,参数形式列表,委托类型名,当然还有一个关键字delegate必不可少,和一个可选的访问修饰符public,好了,我们定义好了一种委托类型,这种类型名称叫做EventHandler,你也可以把它理解为一个类,现在我们有了一个类,这还不够,要想定义事件,我们还必须要它的一个实例,所以我们定义:

public event EventHandler EventName;

这里也有三个要素,首先我们定义的是一个委托,所以我们声明 EventHandler EventName; ,就像声明 int i ; 得到一个整型变量 i 一样,我们得到了一个委托的实例,可是这个委托是特殊的,它不仅仅是一个委托,更是一种特殊的委托:事件,所以我们在前面又加上了event关键字,表明这是一个事件,可是还有最后一件事,这个事件是要被别人访问到的,因为我们需要在它上面注册事件,如前面所说,我们需要在它上面放上我们的函数指针,所以我们最后在前面又加上了一个public关键字。当然,如果我们只希望这个事件被类中的成员访问到,也不需要声明public,但一般事件就是用来通信的,失去了public也就失去了它存在的意义。当然,也可以把事件设为静态的,这样在声明的时候增加一个static关键字,这样,对发生事件的类的所有对象的实例,我们都可以用它来进行通信。

5.如何发出事件?

发出事件即执行委托。当事件发生时,执行委托EventHandler(this,new EventArgs()),这段代码告诉观察者们,我(this)发生变化了,变化的信息(new EventArgs()),给你们送过来了,这样,所有观察者感知到了变化,拿走变化的信息,执行相应的处理。

6.由事件生成事件?

如果没有奇点爆炸产生宇宙这一事件发生,也就不会有现在的宇宙,更不会有现在的无穷变化。所以,一个变化引发另一个变化,一个事件引发另一个事件,我理解为事件的传递性。在编程中理解这一点也是非常重要的。有时,如果你想定义自己的一种事件,就必须捕获特定的事件并发出事件,如果已经有事件处理的代码,那么你可以重写事件处理的代码,如重写OnPaint()函数,来达到你自己的事件处理目的。

posted on 2010-02-28 16:03  yry  阅读(544)  评论(3编辑  收藏  举报