介绍.NET中的委派(Delegates)之二
使用委派调用静态方法
StaticCallbacks方法示范了用各种不同方式的回调委派。这个方法首先构造一个Set对象,告诉它对象创建有五个对象元素的数组。然后调用ProcessItems,在第一个调用中,它的feedback参数为null。ProcessItems呈现一个方法,这种方法为每一个Set操纵的项目实现某种动作。在第一个例子中,因为feedback参数是null,在处理每一个项目时不调用任何回调方法。
第二个例子中创建了一个新的Set.FeedBack委派对象,这个委派对象是一个方法包装器,允许方法的调用是经由这个包装器间接调用。对于类型FeedBack的构造器来说,方法的名字(App.FeedBackConsole)被作为构造器的参数传递;这就表示方法被包装。然后,从new操作符返回的引用被传到ProcessItems。现在,当执行ProcessItems时,它会调用App类型的FeedbackToConsole方法处理集合中的每一个项目。FeedbackToConsole简单地将一个串输出到控制台,表示哪个项目被处理了以及这个项目的值是什么。
第三个例子与第二个例子基本相同。唯一的差别是Feedback委派对象包装的是另一个方法:App.FeedbackToMsgBox。这个方法建立一个串,用这个串表示哪个项目被处理以及这个项目的值是什么。然后将这个串显示在一个信息框中。
第四个例子也是静态调用的最后一个例子示范了如何将委派链接在一起形成一个链。在这个例子中,首先创键一个Feedback委派对象的引用变量fb,并将它初始化为null。这个变量指向委派链表的头。Null值表示链表中没有节点。然后,构造Feedback委派对象,由这个对象包装对App FeedbackToConsole方法的调用。C#中,+=操作符被用于将对象添加到fb引用的链表中。Fb此时指向链表的头。
最后,构造另一个Feedback委派对象,由这个对象包装对App FeedbackToMsgBox方法的调用。C#中的+=操作符又一次被用于将对象添加到fb引用的链表中,并且fb被新的链表的头更新。现在,当执行ProcessItems时,传递给它的是Feedback委派链表的头指针。在ProcessItems内部,调用回调方法的代码行实际上终止调用所有的在链表中由委派对象包装的回调方法。也就是说,对于被迭代的每一个项目,都会调用FeedbackToConsole,接着马上调用FeedbackToMsgBox。在后续文章中我将详细讨论委派链的处理机制。
有一点很重要,那就是在这个例子中每件事情都是类型安全的,例如,当构造Feedback委派对象时,编译器保证App的FeedbackToConsole和FeedbackToMsgBox方法都具备确切的原型,像由Feedback委派定义的一样。既两个方法必须有三个参数(Object,Int32和Int32),并且两个方法必须有相同的返回类型(void)。如果方法原型不匹配,则编译器将发出下面的出错信息:“error CS0123:The signature of method ’App.FeedbackToMsgBox()’ does not match this delegate
type。”——意思是App.FeedbackToMsgBox()方法的签名与委派的类型不匹配。
调用实例方法
前面我们讨论了如何使用委派调用静态方法。但是委派还能被用于调用特定对象的实例方法。在调用实例方法时,委派需要知道这个它要用方法操作的对象的实例。
为了理解实例方法的回调机制,让我们回头看看前面代码中的InstanceCallbacks方法。这段代码与静态方法的情形极其相似。注意在Set对象被创建之后,App对象被创建。这个App对象仅仅是创建而已,处于示例目的没有其它内容。当新的Feedback委派对象被创建的时候,它的构造齐备传到appobj.FeedbackToFile。这将导致这个委派包装对FeedbackToFile方法的引用,FeedbackToFile是个实例方法(非静态)。当这个实例方法被调用时,由appobj引用的对象被操作(作为隐藏传递参数)。FeedbackToFile方法的作用有点像FeedbackToConsole 和 FeedbackToMsgBox,不同的是它打开一个文件并将处理的项目串添加到文件尾。
揭开委派的神秘面纱
从表面上看,委派好像很容易使用:用C#委派关键字定义,用类似new操作符的方式构造它们的实例, 用类似方法调用的语法调用回调方法(不同的是不使用方法名,而是使用指代委派对象的变量)。
然而,委派的实际运行机制要比前述例子中所描述的过程要复杂的多。编译器和公共语言运行时(CLR)在幕后所做的许多处理隐藏了这些复杂性,在这一部分中,我们将集中精力来讨论编译器和CLR是如何协同工作实现委派机制的。这些知识将极大地丰富你对委派的理解并且这些知识将告诉你如何有效地使用它们。我们还将涉及到一些在编程中能用到的委派的附加特性。
我们还是从下面这行代码开始:
public delegate void Feedback(
Object value, Int32 item, Int32 numItems);
当编译器看到之一行代码时,它会产生一个完整的类定义,这个定义的代码会像下面这个样子:
//
public class Feedback : System.MulticastDelegate {
// 构造器
public Feedback(Object target, Int32 methodPtr);
// 方法与
- 发表评论
-
- 最新评论 更多>>