您的位置:首页 > 编程语言 > C#

探寻C#事件本质1

2014-09-03 15:57 351 查看
我最先在学习C#事件的时候,阅读了许多书籍,但总是不能对事件建立起一个比较清晰的概念,对其内部机制和原理也是似是而非,因为这些书籍在描述事件的时候总是夹杂许多其他不能理解的抽象术语,相信许多初学者都有这样的感觉。

同时,在利用IDE进行GUI编程时,IDE总是在内部帮助我们实现了事件必须的一些代码,我们只需双击对象,编事件处理函数就行了,而我们常常对内部的工作一无所知,或没有去主动理解这些自动生成的代码。

现在我试着回答学习时遇到的几个问题,这将会有助于你理解到底什么是事件。

如何定义一个事件?

语法:修饰符 event关键字 委托类名 事件名;

比如:public event somedelegatename myeventname;

事件到底是什么类型(引用?值?)

事件其实就是一个特殊的委托。

MSDN中的C#参考里这样描述:事件是特殊类型的多路广播委托,仅可从声明它们的类或结构(发行者类)中调用。如果其他类或结构订阅了该事件,则当发行者类引发该事件时,会调用其事件处理程序方法。

对于这一点,我们也可以从事件的定义中看出,不过就是在定义委托对象时加了event关键字表明这个委托现在叫事件。

何谓事件的订阅(subscribe)?

我们用VS2005建立一个只有一个按钮的winform程序,双击按钮,设计器会在Form1.Designer.cs中自动生成一行代码

this.button1.Click += new System.EventHandler(this.button1_Click);

这就是事件的订阅!其实就是用事件处理函数this.button1_Click来实例化一个委托System.EventHandler(这个函数与委托拥有同样的签名,为什么需要有同样签名,我理解就是要保证委托与函数的类型一致,这样才能把函数句柄赋给一个委托对象,即所谓的用委托封装方法或C++中把一个方法句柄赋给一个函数指针),并把这个委托对象赋给事件Click(因这Click其实就是一个委托引用,所以可以这样做,从C++的角度来理解,就是把事件处理函数赋给了一个函数指针变量,这样就可以通过调用这个函数指针以执行事件处理函数)

一句话,订阅事件就是将某个委托对象指向一个具体的方法。

什么是引发事件?

当程序中满足某个条件时调用事件就是引发了事件,为什么可以调用事件呢?因为事件就是一个委托,而委托具有C++中函数指针的作用,调用委托就是调用委托中封装的事件处理函数

为什么事件可以被多个对象订阅?

知道了事件实际是一个多播委托后,这个问题不难理解,所谓被多个对象订阅,就是事件被触发后,可以导致多个对象做出反应,也就是多个对象的某个事件处理函数被调用。为什么会这样呢,因为事件是多播委托,即封装了多个函数的委托,调用这个委托实际上就是在调用被封装的这多个函数。

下面用一个最简单的控制台程序例子来说明事件的运作方式

using System;
namespace 最简单的自定义事件
{
/// <summary>
/// 事件发送类,即调用事件的类
/// </summary>
class Class1
{
public delegate void mydelegate(object sender,EventArgs e); //定义委托
public event mydelegate myevent; //定义一个委托类型的事件,即定义一个委托对象

public void run()
{
//死循环,不停测试某个条件是否满足,即所谓的监听
while(true)
{
if(Console.ReadLine()=="a")
{
myevent(this,new EventArgs()); //调用事件
}
}
}
}

/// <summary>
/// 事件接收类,即事件处理的类
/// </summary>
class Class2
{
static void Main(string[] args)
{
Class1 c1 = new Class1();
c1.myevent+= new Class1.mydelegate(c1_myevent); //将委托对象指向具体的事件处理函数,即所谓的订阅事件
c1.run();//运行这个事件,因为此时委托已经指向了具体方法,可以运行了
}

private static void c1_myevent(object sender, EventArgs e)
{//事件处理方法
Console.WriteLine(" 你触发了事件!");
}
}
}


对于这个例子,为了加深理解事件的本质,我们可以把事件订阅c1.myevent+= new Class1.mydelegate(c1_myevent); 这句注释掉,即事件没有指向任何具体的方法,编译,不会报错,运行它,如果我们不输入
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: