=========
@ 委托链
=========
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);
}
// 组合 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 字段会指向原先的委托链的头部,但此时创建了一个新的委托对象。
下面通过代码演示:














































































































委托链调用描述(伪代码)
// 无返回值。
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();
}
}
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
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();
}
}
显示调用委托链表的委托对象
========================
@ 显示调用委托链表委托对象
========================












































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