cow-man

也谈委托,事件和回调

  今天面试问了别人问了个问题,让我举个委托的例子。我是这样说的,委托本质上就是一个函数引用,A类要想使用B类的某个方法,必须在A类中申明一个B类方法的引用才能使用,这个引用就是委托了。对方叫我说具体点,我变想边说,结果对方没有听太明白,应该是我自己思路太乱吧,在这里整理一下这个思路。

 

  还是从委托的概念出发,这才是委托的本质,也是最不容易忘记的。

  委托变量函数引用。这四个字够简单吧,估计看了之后想忘记挺难的,很容易推理到委托就是函数类型

  举个例子:Int变量是3的引用,那么Int是3类型。(当然int类型是值类型,这里只是做一个推理)

 

  对于一个具体函数,他对应的委托有应该如果定义呢?那就应该想什么特性是某类函数共有的:函数签名相同。

  至于返回值是否要求相同,暂时不知,因为一般委托都没有返回值。有机会实验一把。

  

  那么怎么使用委托呢?例如:A类有个方法C,B类需要使用方法C,那么B类需要有一个C的引用。

  伪代码如下:

  public class A

  {

    private void C(int i) {}

  }

  

  // 有了方法,才有定义委托的必要了。

  public delegate void DC(int i);  // 这一点得记住了,委托类型就是这样定义的,就是函数类型的定义。这里面delegate说明申明的是一个函数类型。

                 // 可以这样理解:delegate后面就是一个函数签名,用于描述该函数的类型,其中dc就是函数类型名,即委托名了。

  public Class B

  {

    private DC dc;  // 通过委托类型定义委托变量

  }

 

  现在我们需要做的事情就是将A对象的函数C复制给B对象的变量dc,因为两个变量都是私有的,所以无法做到。所以可以把委托变量暴露出来,然后在A对象中复制使用。这其中就需要A知道B,即A到B的一个单向关联的关系。当然也可以把A类中C方法暴露出来,这个时候可以直接访问C方法,就没有使用委托的必要了。

  public class A

  {

    public B _b;

    private void C(int i) {}

    public Set()

    {

      //_b.dc=c; 这显然错误,因为委托是引用类型,所以必须用new关键字来创建并赋值。

      _b.dc=new DC(C);  // 这样就将A类中函数复制给了B类中的委托变量,B类中就可以使用A类中对应的函数了。

    }

  }

 

  public Class B

  {

    public DC dc;  // 通过委托类型定义委托变量

  }

 

  下面的写出使用的代码。

  B b=new B(); //

  A a=new A();

  a._b=b;

  a.Set();

  b.dc(i); //  相当于a.C(i);

  B要调用A中的私有的C方法,B只能申明一个public类型的C方法委托变量。然后让A知道B,在A中将A的C方法复制给B对象。

  理解:(1)B无法直接访问A中的私有方法C,但可以通过申明一个C方法类型的委托变量,让委托变量访问C方法。

     (2)将C中的私有方法复制给A对象的委托变量的工作在哪里做? 在C类中做,因为如果在外面做,还是无法访问C方法。那就需要A知道B,即在A中有B的引用。

 

现在再谈谈事件事件的意义大概是这样的:B象做了一个操作,A象如果订阅了这个事件,那么就可以得到通知并做相应的处理,其中这个操作就是事件。

从定义中可以看出,B某个操作,说明正在执行B的方法,然后A的做相应的处理,说明可以触发B中的方法。总结起来,就是B以在不知道A前提下,调用B中的方法。再简洁一点,B以调用A的私有方法,这正需要委托来实现

事件本质上也是一个委托,只是它重写“+=”运算符,实现事件的订阅(函数的赋值)。

事件的申明:

  public Class B

  {

    public event C dc;  // 在委托签名添加event关键字,dc就是事件了

  }

 

   public class A

  {

    public B _b;

    private void C(int i) {}

    public Set()

    {

      //_b.dc=c; 这显然错误,因为委托是引用类型,所以必须用new关键字来创建并赋值。

      //          _b.dc=new DC(C);  // 这样就将A类中函数复制给了B类中的委托变量,B类中就可以使用A类中对应的函数了。

      _b.dc+=new DC(c); // 使用运算符+=来实现函数的复制,即事件的签约

    }

  }

  触发事件的方法还是一样的。

  B b=new B(); //

  A a=new A();

  a._b=b;

  a.Set();

  b.dc(i);

 

 接着谈谈回调函数。

  回调函数:一个函数传给另一个函数调用。也就是说在另一个函数中,第一个函数的委托。这个比较简单就不举例子了。

  因为回调是直接传的函数,所以跟event不同,一个event可以有多个事件对象订阅。一个回调,每次只能调用一个对象中的函数。

 

  纯属自己的理解,有问题的地方望大家指正。

posted on 2012-03-02 18:09  cow-man  阅读(220)  评论(0编辑  收藏  举报

导航