深入理解委托(二)

=========
@ 委托链
=========
    MulticastDelegate 对象有一个私有字段 _prev,该字段指向另一个 MulticastDelegate对象的引用。这使得多个委托对象可以组合成为一个链表。
Delegate 类中定义了三个静态方法帮助我们来操作委托链表:
 

class  System.Delegate{
 
//  组合 head 和 tail 所表示的链表,并返回 head。注意:head 将是最后一个被调用的委托对象。
  public   static  Delegate Combine(Delegate tail, Delegate head);

 
//  创建一个由委托数组表示的委托链表。注意:索引为 0 的元素将为链表头部,并将是最后一个被调用的对象。
  public   static  Delegate Combine(Delegate[] delegateArray);

 
//  从链表中移除一个和 value 的回调目标/回调方法相匹配的委托,新的链表头会被返回,并且将是最后一个被调用的委托对象。
  public   static  Delegate Remove(Delegate source, Delegate value);
}

    构造一个新的委托对象时,其 _prev 字段会被初始化为 null,这表示委托链表上没有其他对象,实际上它也一直为 null,不可改变,
当我们使用 Combine 方法时,_prev 字段会指向原先的委托链的头部,但此时创建了一个新的委托对象。
    下面通过代码演示:

Code
// 演示向委托链中添加,移除委托,以及委托链的执行顺序。
using System;
delegate void D1();

public class DelegateCombineTest{
 
public static void f1(){ Console.Write(" <-- f1 "); }
              
public static void f2(){ Console.Write(" <-- f2 " ); }
 
public void f3(){ Console.Write(" <-- [" + this.GetHashCode() + "] f3 "); }

 
public static void Main(string[] args){
  
// 创建两个回调静态方法的委托对象。
  D1 d1 = new D1(f1);
  D1 d2 
= new D1(f2);
  
  
// 返回 d2 作为表头,d1 的 _prev 为 null,d1 和 d2 的 _target 都为 null(静态方法)。
  D1 dlist = (D1)Delegate.Combine(d1,d2);
  dlist(); 
// <-- f1 <-- f2
 
  Console.WriteLine(
"\n");
  
  
// 返回 d1 作为表头。  
  dlist = (D1)Delegate.Combine(d2,d1);
  dlist(); 
// <-- f2 <-- f1
  
  Console.WriteLine(
"\n");

  
// 创建两个回调实例方法的委托对象。
  DelegateCombineTest inst1 = new DelegateCombineTest();
  DelegateCombineTest inst2 
= new DelegateCombineTest();  
  D1 d3 
= new D1(inst1.f3);
  D1 d4 
= new D1(inst2.f3);  
  
  
// 实例方法,d3 的 _target 为 inst1/inst2。
  
// 注:不知道该如何获取当前实例的名称如,inst1 和 inst2,这里用 GetHashCode()。
  dlist = (D1)Delegate.Combine(dlist,d3);
  dlist(); 
// <-- f2 <-- f1 <-- [58225482] f3

  Console.WriteLine(
"\n");
  
  dlist 
= (D1)Delegate.Combine(dlist,d4); 
  dlist(); 
// <-- f2 <-- f1 <-- [58225482] f3 <-- [54267293] f3

  Console.WriteLine(
"\n");

  D1[] darr 
= new D1[4];
  darr[
0= d1;
  darr[
1= d2;
  darr[
2= d3;
  darr[
3= d4;
  
  
// 接受一个委托数组作为参数的 Combine(Delegate[] darr) 方法。
  dlist = (D1)Delegate.Combine(darr);
  dlist(); 
// <-- f2 <-- f1 <-- [58225482] f3 <-- [54267293] f3

  Console.WriteLine(
"\n");

  
// 从委托链上移除对象。
  dlist = (D1)Delegate.Remove(dlist, new D1(f1)); 
  
// 创建对象就是为了将其从委托链中移除(看起来很奇怪吧)。
  dlist(); // <-- f2 <-- [58225482] f3 <-- [54267293] f3

  Console.WriteLine(
"\n");
  
  
// 由于回调方法是实例方法,用新实例的方法作为委托的回调方法,并不会被移除。
  dlist = (D1)Delegate.Remove(dlist, new D1(new DelegateCombineTest().f3)); 
  dlist(); 
// <-- f2 <-- [58225482] f3 <-- [54267293] f3

  Console.WriteLine(
"\n");

  
// 使用原来的实例的方法作为委托的回调方法创建委托对象,以移除委托链中相应的委托对象。
  dlist = (D1)Delegate.Remove(dlist, new D1(inst1.f3)); 
  dlist(); 
// <-- f2 <-- [54267293] f3
  
  Console.WriteLine(
"\n");

  
// 如果委托链中有相同的委托对象,将移除最近一次加入到委托链中的委托链,
  
// 即靠近链表头的委托链。从委托链的 head 向 _prev 搜索匹配对象,
  
// 将找到的第一个委托链删除。如果未找到要删除的对象,将返回传递给它的第一个参数。
  D1[] darr2 = new D1[4];
  darr2[
0= new D1(f1);
  darr2[
1= new D1(inst1.f3);
  darr2[
2= new D1(f1);
  darr2[
3= new D1(inst1.f3);
  
  dlist 
= (D1)Delegate.Combine(darr2);
  dlist(); 
//  <-- f1  <-- [58225482] f3  <-- f1  <-- [58225482] f3

  Console.WriteLine(
"\n");

  dlist 
= (D1)Delegate.Remove(dlist, new D1(inst1.f3)); 
  dlist(); 
//  <-- f1  <-- [58225482] f3  <-- f1

  Console.WriteLine(
"\n");

  dlist 
= (D1)Delegate.Remove(dlist, new D1(f1)); 
  dlist(); 
//  <-- f1  <-- [58225482] f3  
 }

}
 

委托链调用描述(伪代码)

//  无返回值。
class  D1 : MulticastDelegate{
    
public   void   virtual  Invoke(){
        
//  如果该委托对象不是委托链表的 head,
        
//  那么调用前一个委托对象的 Invoke()。
         if (_prev  !=   null ){
            _prev.Invoke();
        }
        
//  调用自身的回调函数。
        _target.methodPtr();
    }


//  有返回值。
class  D1 : MulticastDelegate{
    
public  ReturnType  virtual  Invoke(){
        
//  如果该委托对象不是委托链表的 head,
        
//  那么调用前一个委托对象的 Invoke()。
         if (_prev  !=   null ){
            _prev.Invoke();
        }
        
//  调用自身的回调函数,前一个返回值将被丢弃。
         return  _target.methodPtr();
    }
}

C#委托操作符
// C# 编译器会把 += 翻译为对 Delegate.Combine 方法的调用,
// -= 翻译为 Delegate.Remove 方法的调用。

Code
Code
using System;
delegate void D1();

public class DelegateCombineTest{
 
public static void f1(){ Console.Write(" <-- f1 "); }
              
public static void f2(){ Console.Write(" <-- f2 " ); }
 
public void f3(){ Console.Write(" <-- [" + this.GetHashCode() + "] f3 "); }

 
public static void Main(string[] args){
  
// 创建两个回调静态方法的委托对象。
  D1 d1 = new D1(f1);
  D1 d2 
= new D1(f2);  

  
// 创建两个回调实例方法的委托对象。
  DelegateCombineTest inst1 = new DelegateCombineTest();
  DelegateCombineTest inst2 
= new DelegateCombineTest();  
  D1 d3 
= new D1(inst1.f3);
  D1 d4 
= new D1(inst2.f3);
  
  
// D1 dlist = new D1(); // 注意不可以这样。  
  D1 dlist = new D1(f1);
  
  dlist 
+= d1;  
  dlist(); 
// <-- f1 <-- f1
 
  Console.WriteLine(
"\n");

  dlist 
= d1 + d2 + d3 + d4;
  dlist(); 
//  <-- f1  <-- [58225482] f3  <-- f1  <-- [54267293] f3
  
  Console.WriteLine(
"\n");

  dlist 
= dlist - (d2 + d3);
  dlist(); 
//  <-- f1 <-- [54267293] f3

  Console.WriteLine(
"\n");

  dlist 
-= d1;
  dlist();
 }
}

显示调用委托链表的委托对象
========================
@ 显示调用委托链表委托对象
========================

Code
using System;
delegate void D1();

public class DelegateCombineTest{
 
public static void f1(){ Console.Write(" <-- f1 "); }
              
public static void f2(){ Console.Write(" <-- f2 " ); }
 
public void f3(){ Console.Write(" <-- [" + this.GetHashCode() + "] f3 "); }

 
public static void Main(string[] args){
  
// 创建两个回调静态方法的委托对象。
  D1 d1 = new D1(f1);
  D1 d2 
= new D1(f2);  

  
// 创建两个回调实例方法的委托对象。
  DelegateCombineTest inst1 = new DelegateCombineTest();
  DelegateCombineTest inst2 
= new DelegateCombineTest();  
  D1 d3 
= new D1(inst1.f3);
  D1 d4 
= new D1(inst2.f3);
 
  D1 dlist 
= new D1(f1);

  dlist 
= d1 + d2 + d3 + d4;

  Delegate[] darr 
= dlist.GetInvocationList();
  
foreach(D1 d in darr){
   d();
   Console.WriteLine(
"\n");
  }

 }

}
 

输出:
 <-- f1
 <-- f2
 <-- [58225482] f3
 <-- [54267293] f3

转载于:https://www.cnblogs.com/kimma/archive/2008/09/10/1288669.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值