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

.Net学习难点讨论系列1 – 委托与事件之事件

2011-05-24 20:58 337 查看
http://www.cnblogs.com/lsxqw2004/archive/2008/12/07/1349753.html

 

在大家学习与掌握.Net的过程中,理解委托与事件的概念,并恰当的使用它是跨越新手门槛额关键,下面结合我学习时的理解及几个经典的委托与事件的使用例子讲述一下。也算是对自己学习的一个总结。

委托与事件是实现观察者模式的一种非常好的工具,委托充当了抽象的Observer(观察者)的接口,提供事件的对象充当了目标对象。一个对象(目
标对象)的状态发生改变,所有依赖对象(观察者对象)都将得到通知(TerryLee)。即当观察者中符合事件声明中委托的类型的方法订阅了目标对象的事
件后。当目标对象事件触发时(由于状态改变),会执行观察者中相应的方法(即通知观察者对象)。

下面的例子来自于TerryLee的文章,李哥的代码经典,拿出来分析学习一下J


using
 System; 

using
 System.Collections.Generic; 

using
 System.Text; 

namespace
 ConsoleApplication1 



class
 Program 



static
 
void
 Main(
string
[] args) 



//
目标对象 

Stock stock 
=
 
new
 Stock(
"
Microsoft
"

120.00
); 

//
观察者 

Investor investor 
=
 
new
 Investor(
"
Jom
"
); 

//
观察者订阅目标对象的事件 

//
此处将观察者与目标对象关联了起来 

stock.NotifyEvent 
+=
 
new
 NotifyEventHandler(investor.SendData); 

//
此操作触发事件 -- 观察者会响应此事件 

stock.Update(); 

Console.ReadLine(); 





public
 
delegate
 
void
 NotifyEventHandler(
object
 sender); 

public
 
class
 Stock 



//
此处声明一个事件(省略了event关键字) 

//
此为目标对象处 

public
 NotifyEventHandler NotifyEvent; 

private
 String _symbol; 

private
 
double
 _price; 

public
 Stock(String symbol, 
double
 price) 



this
._symbol 
=
 symbol; 

this
._price 
=
 price; 



public
 
void
 Update() 



OnNotifyChange(); 



//
触发一个事件的操作 

public
 
void
 OnNotifyChange() 



if
 (NotifyEvent 
!=
 
null




//
实际触发的操作 -- 在检测事件(委托对象)不为空后触发 

//
传给事件(委托对象)的参数是目标对象,最终此对象被传递给观察者处理此事件的方法 

NotifyEvent(
this
); 





public
 String Symbol 


get
 { 
return
 _symbol; } } 

public
 
double
 Price 


get
 { 
return
 _price; } } 



//
观察者 

public
 
class
 Investor 



private
 
string
 _name; 

public
 Investor(
string
 name) 



this
._name 
=
 name; 



//
观察者中在事件触发时,处理目标对象的函数 

//
此处接受的参数为触发事件时传入的参数 

public
 
void
 SendData(
object
 obj) 



if
 (obj 
is
 Stock) 



Stock stock 
=
 (Stock)obj; 

Console.WriteLine(
"
Notified {0} of {1}'s 
"
 
+
 
"
change to {2:C}
"
, _name, stock.Symbol, stock.Price); 









 

事件详解:

以下伴随一个示例说明定义一个事件的步骤:

示例来自C# via CLR,示例完成的功能:Fax,Pager两个对象订阅MailManager的事件。新邮件抵达时MailManager触发事件,MailManager将此通知送到订阅它的对象,这些对象以自己的方式处理邮件。

第一步:定义一个类型用于存放所有需要发送给事件通知接收者的附加信息

    按照约定,所有传递给事件处理程序的用于存放事件信息的类都应该继承自System.EventArgs,并且类的名称应该以
EventArgs结束。定义一个不需要任何额外信息的事件(如Button的Click事件)时,可以直接使用EventArgs.Empty,不用构
建一个新的EventArgs类。

 

//
 第一步:定义一个类型用于存放所有需要发送给事件通知接收者的附加信息 

internal
 
class
 NewMailEventArgs : EventArgs { 

    
private
 
readonly
 String m_from, m_to, m_subject; 

    
public
 NewMailEventArgs(String from, String to, String subject) 

  { 

        m_from 
=
 from; 

     m_to 
=
 to; 

   m_subject 
=
 subject; 

     } 

    
public
 String From 

  { 

    get
 { 
return
 m_from; } 

  } 

    
public
 String To 

  { 

    
get
 { 
return
 m_to; } 

  } 

    
public
 String Subject 

  { 

    
get
 { 
return
 m_subject; } 

  } 



 

第二步:定义事件成员

事件成员使用C#关键字event定义。

一个事件的定义包括以下部分:

一个给定的可访问性(通常都为public)

一个表示即将被调用方法的原型的委托类型(其含义是所有事件通知的接收者都必须提供一个原型和此委托类型相匹配的回调方法)

一个事件成员的名称(可以是任意有效的标识符)

代码

 

//
 第二步: 定义事件成员 

    
public
 
event
 EventHandler
<
NewMailEventArgs
>
 NewMail; 

 

几个委托类型的约定定义方法:

sender参数的类型为Object

派生自EventArgs类的参数命名为e

事件处理程序的返回类型都为void

第三步:定义一个负责引发事件的方法来通知已订阅事件的对象事件已经发生

 

//
 第步:定义一个负责引发事件的方法,来通知已订阅事件的对象已经发生。 

    
protected
 
virtual
 
void
 OnNewMail(NewMailEventArgs e) { 

        
//
 处于线程安全考虑,将委托字段保存到一个临时字段中 

        EventHandler
<
NewMailEventArgs
>
 temp 
=
 NewMail; 

        
//
 通知所有已订阅事件的对象 

        
if
 (temp 
!=
 
null
) temp(
this
, e); 

    } 

    
//
 定义了一个方法将输入转化为期望事件 

  public
 
void
 SimulateNewMail(String from, String to, String subject) { 

  //
 构建一个对象来存放我们希望传递给通知接收者的信息 

  NewMailEventArgs e 
=
 
new
 NewMailEventArgs(from, to, subject); 

  //
 调用方法以通知对象事件已发生 

  OnNewMail(e); 

 

 

监听事件的类型的设计

//
 构建一个EventHandler<NewMailEventArgs>委托的实例,该委托指向FaxMsg回调方法 

//
 然后对MailManager的NewMail时间注册回调方法 

mm.NewMail 
+=
 FaxMsg; 

 

 

注以上代码内部使用了委托推断。

以下是注销
MailManager

NewMail
事件的代码

 

mm.NewMail 
-=
 FaxMsg; 

 

说明:

事件触发时,订阅该事件的函数会自动执行。事件并不关心有多少函数订阅它。它只管发出这个事件被触发的通知。

 

参考资料:

TerryLee:.NET设计模式(19):观察者模式(Observer Pattern)

C# via CLR(第二版)- 清华大学出版社

//
 当新的电子邮件到达时,MailManager将调用这个方法 

private
 
void
 FaxMsg(Object sender, NewMailEventArgs e) { 

Console.WriteLine(
"
Faxing mail message:
"
); 

Console.WriteLine(
"
 From={0}, To={1}, Subject={2}
"
, e.From, e.To, e.Subject); 

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息