链式委托的执行顺序是怎样的

分析问题

  在前文中已经介绍了链式委托的基本特性是一个以委托组成的链表,而当委托链上的任何一个委托方法被调用时,其后面的所有委托方法将会被依次顺序调用。那读者可能会产生这样的疑问,委托链上的原始顺序是如何形成的呢?回顾一下之前的代码,我们是如何生成一个链式委托的:

            //申明一个委托变量,并绑定第一个方法
            TestMulticastDelegate handler = new TestMulticastDelegate(PrintMessage1);
            //绑定第二个方法
            handler += new TestMulticastDelegate(PrintMessage2);
            //绑定第三个方法
            handler += new TestMulticastDelegate(PrintMessage3);

            //检查结果
            handler();

  相信这里的+=是造成困惑的主要原因,即便把它替换成TestMulticastDelegate handler=new TestMulticastDelegate(PrintMessage1)+new TestMulticastDelegate(PrintMessage2);读者可能仍然很难分辨究竟第一个委托被排在了链表的前面,还是第二个委托被排在了前面。C#语言的设计师们在重写委托的+时,确实没有考虑到在数学意义上加号左右参数的可交换性。为了清除起见,来看一下下面的代码:

            TestMulticastDelegate handler1 = new TestMulticastDelegate(PrintMessage1);
            TestMulticastDelegate handler2 = new TestMulticastDelegate(PrintMessage2);

            Delegate d = System.MulticastDelegate.Combine(handler1, handler2);
            d.DynamicInvoke();

  不错,这段代码本质上和第一段代码完全相同,并且更容易理解。Delegate MulticastDelegate.Combine(Delegate a,Delegate b)函数将串联两个委托,并且把第一个委托放在第二个委托之前,读者可以把两个委托的相加理解为Delegate MulticastDelegate.Combine(Delegate a,Delegate b)的调用。至此,链式委托的执行顺序及其由来就非常清晰了。

  接下来,为了更彻底地理解链式委托的实现机制,有必要来看一下System.MulticastDelegate的内部成员,下图展示了System.MulticastDelegate中三个重要的内部成员。

  在本节前文中已经介绍了System.Delegate的两个内部成员:_target和_methodPtr。System.MulticastDelegate继承了这两个成员,并且添加了一个_prev成员,该成员是一个委托的引用变量,当某个委托被串联到当前委托的后面时,该成员会被设置指向那个后续委托实例对象。.NET就依靠这一引用来逐一找到当前委托的所有后续委托并依次执行。

  回到本节开始所提到的问题,程序员是否有能力控制链式委托的执行顺勋呢?读者可能会脱口而出,只要在定义链式委托时小心地按照需求希望的顺序来依次添加委托就可以了,完全正确,但如果在定义完链式委托后,突然希望改变执行顺序呢?又或者,程序需要按照实际运行情况来决定链式委托的执行顺序呢?答案就是,程序员需要手动地来做这个工作。来看以下代码:

            TestMulticastDelegate hanlder = new TestMulticastDelegate(PrintMessage1);
            hanlder += new TestMulticastDelegate(PrintMessage2);

            Delegate[] h = hanlder.GetInvocationList();

  该程序调用了定义在System.MulticastDelegate中的GetInvocationList(),用以获得整个链式委托中的所有委托。这样程序员就可以以任何希望的顺序来执行链式委托了。一个需要读者注意的地方是:Delegate[] GetInvocationList()是一个实例方法,所以其返回的是当前委托在委托链上的所有后续委托,而挂在该委托之前的委托(如果存在的话),程序员将不会也没有必要得到。

答案

  链式委托的执行顺序是:按照委托链上的顺序从当前委托开始依次往后执行。如果有需要,可以通过GetInvocationList()方法来获得委托链上的所有需要执行的委托,并且按照任何希望的顺序去执行它们。

时间: 2024-10-14 00:23:33

链式委托的执行顺序是怎样的的相关文章

什么是链式委托

分析问题 在前文中,笔者已经详细地介绍了委托的基本概念.而所谓的链式委托,即是一个由委托组成的链表.所有的自定义委托都直接继承自System.MulticastDelegate类型.这个类型即是为链式委托而设计的.所以说,所有的自定义委托都天生地具备了成为一个链式委托的能力.当当个以上的委托被链接到一起形成一个委托链时,调用头部的委托将导致该链上的所有委托方法都被执行. 现在来看一个实际例子,如下代码所示: using System; namespace Test { class Multica

链式基数排序收集的顺序有什么规律

okkq8b室瘴颊蕾簇恐<http://weibo.com/p209p688p/230927983167992529424384?yv20180413> 39798z裁橙僦庇剿料<http://weibo.com/p402p589p/230927983211814600839168?jy20180413> eaj76c猩莆税诶放吮<http://weibo.com/pnwp/230927983045771983069184> gs54z3放撼涡窘赐淘<http:/

数据结构Java实现07----队列:顺序队列&amp;顺序循环队列、链式队列、顺序优先队列

数据结构Java实现07----队列:顺序队列&顺序循环队列.链式队列.顺序优先队列 一.队列的概念: 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作. 队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头.队列的插入操作通常称作入队列,队列的删除操作通常称作出队列. 下图是一个依次向队列中插入数据元素a0,a1,...,an-

顺序队列和链式队列的实现

队列是一种常用的数据结构,它跟栈一样,操作都受到限制,队列只允许从一端进数据,另一端出数据.队列跟栈不同,栈是一种"后进先出"的模式,而队列是一种"先进先出"的操作模式.就好比日常排队一样,先排队的先出,后排队的后出.例如,进入队列的顺序是1,2,3,4,5则出队列的顺序是1,2,3,4,5(只考虑一次性出列的情况). 队列也分顺序队列和链式队列,跟顺序栈和链表栈一样,顺序队列同样是基于数组实现,链式队列则是基于链表实现. 顺序队列: //顺序队列 #include

顺序存储结构与链式存储结构

上一篇博客简单讲述了一下两种结构的概念这一篇博客主要想讲述一下他们之间的区别 顺序存储结构与链式存储结构的优缺点 顺序存储结构 概念官方一点来说可以使用百度百科的介绍:顺序存储结构是存储结构类型中的一种,该结构是把逻辑上相邻的结点存储在物理位置上相邻的存储单元中,结点之间的逻辑关系由存储单元的邻接关系来体现. 当然不得不说一般这种官方的解释都是不太适合我的,所以用小甲鱼的方式来说这个概念的话,简单来说就是,用一段连续的地址存放数据元素,数据间的逻辑关系和物理关系相同. 优点1:存储密度大,空间利

线性表的Java实现--链式存储(单向链表)

线性表的Java实现--链式存储(单向链表) 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始. 链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素.由于不需要按顺序存储,链表在插入.删除数据元素时比顺序存储要快,但是在查找一个节点时则要比顺序存储要慢. 使用链式存储可以克服顺序线性表需要预先知道数据大小的缺点,链表结构可以充分利用内存空间,实现灵活的内存动态管理.但是链式存储失去了数组随机存取的特点,同时增加了节点的指针域,空

关于子类对象的构造函数和父类构造函数的执行顺序

我们分别为父类和子类添加显式的构造函数,代码如下: class Person     {         private int nAge;         protected string strName;         double douHeight;         public string strEateType;         //父类的构造函数         public Person()         {             Console.WriteLine("我

数据结构Java实现05----栈:顺序栈和链式堆栈

数据结构Java实现05----栈:顺序栈和链式堆栈 一.堆栈的基本概念: 堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除操作. 先进后出:堆栈中允许进行插入和删除操作的一端称为栈顶,另一端称为栈底.堆栈的插入和删除操作通常称为进栈或入栈,堆栈的删除操作通常称为出栈或退栈. 备注:栈本身就是一个线性表,所以我们之前讨论过线性表的顺序存储和链式存储,对于栈来说,同样适

数据结构_线性表的顺序表示和链式表示

/********************************************************************************************************************/ 声明: (1)*.h文件是代码声明, *.cpp文件是代码实现; (2)一般头文件的内容有: ①类型声明; ②函数声明; ③枚举; ④常量; ⑤宏 (3)以下说明是为了方便代码文件的管理而设定的一些规则, 以后代码都会按照此规则编写: 1)Pubuse.h 是几