[转帖][c#]C#类间通信方法初探

涉及的类有2个,一个为Provider, 负责提供信息,另一个为Master,负责接受信息。并把类间需要通信的数据封装成结构,称之为“通信结构”,记作“Information struct”。

 

而且,这2个类可以角色互换,互为provider。

 

获取信息的方式:

1、  正向获取:

直接让Master访问Provider的成员。

a)         Provider暴露一个成员变量或属性。  public Information GetInformation( 参数 ) ;

b)         Provider暴露一个方法:这又分2种方式:一是通过中值,二是通过ref或out参数。     public int GetInformation(out Information info) ;

 

正向获取的主要缺点是:Master不知道何时Provider准备好了数据。

2、  反向获取:

让Provider在准备好数据后,主动提供给Master。在实际使用中使用得最多的就是这种方式:在Master需要数据时,创建一个Provider object,Provider object取得数据并作处理后,将其存入Information object中,然后将该Information object提交给Master,然后该Provider object生命周期结束,接着Master可以处理得到的数据了。

         这是一个简单图书信息管理系统,图1是Master object界面,图2是Provider object界面,当点击图1的“添加”按钮时就会弹出图2所示界面,当用户填写完信息后点击“提交按钮”,即可将一个新的图书信息添加到管理系统中。

此时,Information结构可如下设计:

public   struct  Information 
  { 
     
public   string  book_name ; 
     
public   string  author ; 
     
public   string  date ; 

 

        1.通过类的静态成员变量数据通信

 

这是最简单的直接模拟C++中的利用全局变量进行通信的方法。我们把一个Information对象作为Master的静态成员变量,并将其修饰符设为public ,那么Provider object就可以对其进行写操作,当Provider写操作完成之后,Master就可以处理静态的Information对象了。现在,问题出现了――Master怎么知道Provider完成了写操作呢?回调函数!!!――这是C++程序员的第一反应,在C#中可以吗?可以,只不过C#提供的是一种安全的函数指针,叫委托。我们前面已经指出Provider对象通常都是由Master对象创建的,那么Master对象在创建Provider对象时可以传给Provider对象一个委托实例,当Provider完成写操作之后就可以通过此委托实例完成回调了。这个过程可如图3所示。

             图3  通过类的静态成员变量进行类间通信

(图略)

下面看看这种方法的主要C#伪码。

首先要定义委托:

public delegate void D_Callback() ;

再看Master类:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
class Master 
  {   
     
public static Information object_I ;     
     
public void GetInformation() 
     { 
            D_Callback callback 
= new D_Callback(ProcessInformation) ; 
        Provider object_P 
= new Provider(callback) ; 
        
//如,显示object_P界面 
     } 
     
private void ProcessInformation() 
     { 
        
//处理object_I 
     } 
         

}   

 

接下来看看Provider如何实现:

ContractedBlock.gif ExpandedBlockStart.gif Code
class Provider 
  { 
      
private D_Callback back ; 
      
public Provider(D_Callback yourback)  //构造函数需以“回调函数”作为参数 
      { 
         
this.back = yourback ; 
      }
      
//如当用户点击图2中的“提交”按钮时,将调用以下处理函数 
      private void button1_Click() 
      { 
           
//访问Master.object_I ,并将信息写入 
         back() ;//触发回调函数调用,即调用Master中的ProcessInformation函数 

            
this.close() ;// Provider对象完成任务,可以被GC回收了。 
      } 


 

}

 

这种方法很简单,但至少有2点问题:

1、  使Information object成为Master的public 静态对象不好,因为,不仅Provider类,还有其他可能含有恶意的类都可以向其写入内容,这就丧失了安全性。

2、  Master要将自己的成员函数(作为回调的函数)包装成委托传递给Provider类作为构造函数,这就导致了Master类和Provider类非常紧密的耦合,违背了OOD基本原则。

 

因此再来看一个改良版本:通过堆栈对象复制进行数据通信

在Provider object中将获取数据存放到自己的私有Information object中,再由Information object调用从构造函数传递进来的委托,这样跳转到Master的回调函数时,因为Information是struct,而struct是值类型,所以将会在栈上复制这个Information object,其副本就可以被回调函数访问。这样信息就从Provider传递到Master了。

代码这样写:

public delegate void D_Callback(Information object_I) ;

//此处要将Information对象作为回调函数的参数

 

ContractedBlock.gif ExpandedBlockStart.gif Code
class Master
  {  
     
//不再用静态的Information成员 
     public void GetInformation() 
     {
        D_Callback callback 
= new D_Callback(ProcessInformation) ; 
        Provider object_P 
= new Provider(callback) ; 
         
     } 
     
private void ProcessInformation(Information object_I)   
{                                                     
        
//处理object_I的副本 
     } 
         
}   

 

 

接下来看看Provider的改变:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
class Provider 
  { 
     
private D_Callback back ; 

        
//增加私有Information成员用以存放要传递的信息 
private Information object_I ; 

     
public Provider(D_Callback yourback) 
        { 
        
this.back = yourback ; 
     } 

 
     
private void button1_Click() 
     { 
          
//将信息写入this.object_I 
            
//以object_I作为参数调用Master中的ProcessInformation函数 
         back(this.object_I) ; 
this.close() ; 


 

此方法,通过堆栈object的复制避免了暴露public static member,从而增加了安全性,如此,发布事件的类根本就不必知道预定事件的类的任何情况,将以前的Master和Provider之间的循环依赖转化为单向依赖(仅仅Master依赖于Provider)。

3、 通过事件机制进行通信

在Provider类中声明并发布事件,并在适当的时候触发事件,在Master类中预订事件,并定义事件的处理函数就可以了。这样, Provider类不仅能为Master类所用,还能为其他需要此数据的类服务,可以这样认为:Master类只是Provider的一个client而已。

首先一个委托要成为事件,委托的原型声明必须这样声明:

Public delegate void D_CallBack(object sender, MyEventArgs e);

其中,MyEventArgs必须从EventArgs类继承,它是用来包装要传递的信息,在此,我们这样实现:

public   class  MyEventArgs:System.EventArgs 

   
public  Information object_I; 

接着看看Provider是如何发布事件并触发事件的:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
class Provider 
  { 
     
public event D_Callback  PutOutInformation;  //发布事件 
                                                

     
private void button1_Click() 
     { 
            MyEventArgs  args 
= new MyEventArgs() ; 

              
//将信息写入args.object_I        

        PutOutInformation(
this,args); //触发事件 

this.close() ; 





是不是简单、清晰、明了?!Provider根本就不需要知道Master类的存在。

再来看看Master类如何预定事件,以及事件发生时如何获得所需信息。

 

ContractedBlock.gif ExpandedBlockStart.gif Code
class Master 
{   
     
public void GetInformation() 
     { 
          Privoder object_P 
= new Privoder() ; 
              
//预定事件  
           object_P.PutOutInformation
                
+= new D_Callback(this.ProcessInformation) ; 
              .. 
     } 
private void ProcessInformation(object sender ,MyEventArgs e)     
  {     
         ..
//处理e.object_I                                           
  } 
         
}   

 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhaili1978/archive/2008/11/23/3357772.aspx

转载于:https://www.cnblogs.com/shenyubao/archive/2009/08/12/1544577.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值