中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > 综合其它
实例解析C++/CLI之代理与事件(4)
作者:佚名 时间:2007-09-24 16:37 出处:中国IT实验室 责编:月夜寒箫
              摘要:实例解析C++/CLI之代理与事件(4)

在标号1、2、3中,定义了三个Test类型的对象,并把它们各自与实例函数Test:M包装在单独的代理类型D中。接着,在标号4中,创建了一个四入口的调用列表。

倘若传递进来的调用列表不为空,ProcessList函数将调用在列表中除了特定对象以外的所有函数,例如,在标号5a中,没有排除任何入口,因此所有的函数都会被调用;在标号5b中,t1被排除在外,而标号5c中,与对象t2有关的两个入口都被排除了,结果输出如下:

            

Object t1: 100

Object t2: 100

Object t3: 100

Object t2: 100

Object t2: 200

Object t3: 200

Object t2: 200

Object t1: 300

Object t3: 300

在标号6b中,调用了Clone创建了代理cd4的一个副本,这个函数返回一个Object^,因此,要把它转换成D^类型。当原始及克隆的代理在标号6c、6d中调用时,结果输出如下:

            

Object t1: 5

Object t2: 5

Object t1: 6

Object t2: 6

关于函数ProcessList,如果参数中的代理实例为nullptr,即没有调用列表,那它将直接返回;如果排除的对象为nullptr,那么列表中所有的函数都将被调用;如果存在要排除的对象,就要像标号8中那样把调用列表当作代理数组取出,接着,在标号9中逐个排查不相符的入口,最后,在标号10中调用余下的这些函数。尽管在调用列表中每个入口都是Del类型,但GetInvocationList返回一个基类Delegate数组,所以在调用每个代理实例之前,需像标号10那样先转换成类型D。

事件

在C++/CLI中,事件是一种当某种重要事情发生时,为客户程序提供通知的机制。鼠标单击就是事件的一个典型例子,在事件发生之前,有关的客户程序必须先注册它们感兴趣的事件,如,当检测到鼠标单击时,这些程序就会接到通知。

通过添加或删除一个或多个感兴趣的事件,事件列表可在运行时增长或缩减,请看例7中Server类型的定义,在标号1中,Server类定义了代理类型NewMsgEventHandler(一般约定在用于事件处理时,代理类型添加EventHandler的后缀名),接着,在标号2中,定义了一个名为ProcessNewMsg的公共事件(event在此为一个上下文关键字)。一个事件必须有一个代理类型,实际上,像这样的一个事件已经是一个代理实例了,而且因为它被默认初始化为nullptr,所以它没有调用列表。

例7:

            

using namespace System;

public ref struct Server

{

 /*1*/ delegate void NewMsgEventHandler(String^ msg);

 /*2*/ static event NewMsgEventHandler^ ProcessNewMsg;

 /*3*/ static void Broadcast(String^ msg)

 {

if (ProcessNewMsg != nullptr)

{

 ProcessNewMsg(msg);

}

 }

};

当通过一条消息调用时,函数Broadcast将调用包装在ProcessNewMsg调用列表中所有的函数。

Client类定义在例8中,一个Client的类型实例无论何时被创建,它都会通过向为Server::ProcessNewMsg维护的代理列表中添加一个实例函数(它关联到实例变量),来注册它所感兴趣的新Server消息,而这是通过 += 操作符来完成,如标号5中所示。只要这个入口一直保持在通知列表中,无论何时一个新消息送达Server,注册的函数都会被调用。

例8:

            

using namespace System;

public ref class Client

{

 String^ clientName;

 /*4*/ void ProcessNewMsg(String^ msg)

 {

Console::WriteLine("Client {0} received message {1}", clientName, msg);

 }

 public:

Client(String^ clientName)

{

 this->clientName = clientName;

 /*5*/ Server::ProcessNewMsg += gcnew Server::NewMsgEventHandler(this,

&Client::ProcessNewMsg);

}

/*6*/ ~Client()

{

 Server::ProcessNewMsg -= gcnew Server::NewMsgEventHandler(this,

&Client::ProcessNewMsg);

}

};

要从通知列表中移除一个入口,可使用 -= 操作符,如标号6定义的析构函数中那样。

例9:

            

using namespace System;

int main()

{

 Server::Broadcast("Message 1");

 Client^ c1 = gcnew Client("A");

 Server::Broadcast("Message 2");

 Client^ c2 = gcnew Client("B");

 Server::Broadcast("Message 3");

 Client^ c3 = gcnew Client("C");

 Server::Broadcast("Message 4");

 c1->~Client();

 Server::Broadcast("Message 5");

 c2->~Client();

 Server::Broadcast("Message 6");

 c3->~Client();

 Server::Broadcast("Message 7");

}

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有