掉进陷阱的原因:

  程序猿的高智商。搞软件的都是些聪明人,他们接受新事物快、善于对比类推、懂得举一反三。在看到看到委托如此灵活、便捷的使用方式(附加、移除)时,各种用法都被他们类比、组合了出来。当然,掉进上例中的陷阱太顺其自然了。

  如何自救:

  1、用实验来检验我们的自以为之“是”。对待新事物,既要接受又要质疑,通过这个过程深入把握它的本质,终为我所用。(实验是各求知的利器)

  2、从基础原理上了解委托的本质,以保证我们的“自以为”有科学的依据。(可参考 CLR var C#)

  委托链调用原理:

  1、创建委托(包含委托链)

//添加四个方法
p = new Print(method1);//第一个方法用来实例化委托第一个实例
p += method2;
p += method3;
p += method4;

  1.1 第一行先创建了委托实例p,此时委托p包装了对method1的引用,内部的委托链_invocationList是null。

  1.2 “+=”操作符实现将委托添加到委托链。终p的委托链_invocationList中包含了分别包装着method1、method2、method3、method4的四个委托对象。

  2、调用委托(包含委托链)

/// <summary>
/// 开始执行委托链
/// </summary>
/// <returns></returns>
public string run()
{
      string ismove = "yes";
      p(ref ismove);
      return ismove;
}

  2.1 委托调用方法如p(ref ismove),即委托名(参数)。委托在调用之后会遍历委托链_invocationList依次调用委托链中委托对象所包装的方法来接受参数并执行(若委托链为空时则尝试调用委托对象包装的方法引用)。

  2.2 在遍历委托链期间,任何对委托链的增删操作都是暂时无效的。要再本次遍历结束后才会生效。可以这样理解,在委托触发开始执行时,先会将当前委托链复制到一个临时委托链中,然后对临时委托链进行遍历。这是一种保证线程安全的方法。

  3、委托的移除

p -= method3; //移除方法3
p -= method4;//移除方法4

  3.1 “-=”操作符用于从委托链中移除一个对应的委托对象,如果委托链中有多个对象包装了相同的方法,则移除后添加委托对象;若链表中未找到包装该方法的对象,则不做处理(无异常)。

  通过对委托创建、调用、移除内部过程的简单梳理,不难看出我们曾经自以为的不是,对,问题在过程“2.2”。

  至此,陷阱1“委托链在执行期间可以(根据业务需要)动态增减其中委托实例”分析完了,在method2中移除方法3、4是挡不住委托链依次调用执行的车轮的,只会在再一次调用run时生效。当然,本文只算事论事的讨论而已,在实际很少会出现这样的应用。因为如果要分步骤执行任务会有其他选择,如自己定义任务队列等。