=========
@ 委托链
=========
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 字段会指向原先的委托链的头部,但此时创建了一个新的委托对象。
下面通过代码演示:
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
}
}
// 演示向委托链中添加,移除委托,以及委托链的执行顺序。
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();
}
}
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(); // 注意不可以这样。
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");
}
}
}
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