介绍.NET中的委派(Delegates)之三
用于委派类型的私有域:
域 | 类型 | 描述 |
_target | System.Object | 指回调函数被调用时应该操作的对象。用于实例方法回调 |
_methodPtr | System.Int32 | 内部整型,CLR用它来标示被回调的方法 |
_prev | System.MulticastDelegate | 指另一个委派对象,通常为null |
所有的委派都有代两个参数的构造器:一个参数是对象引用,一个是指代回调方法的整型。但是,如果你检查源代码,就会发现明白诸如App.FeedbackToConsole 或 appobj.FeedbackToFile的传递使用值进行的。你的敏感会告诉你这个代码不能编译!
然而,编译器知道某个委派被创建,同时编译器解析源代码以决定引用哪个对象和方法。对象引用被传递为目标参数,并且用某个特定的Int32值(从某个MethodDef或MethodRef元数据符号获得)标示的方法被传递为methodPtr参数。对于静态方法,null被传递为目标参数。在构造器内部,这两个参数被存储在它们对应的私有(private)域中。
另外,构造器将这个域置为null。这个域被用来创建一个MulticastDelegate对象链表。现在我们暂时忽略_prev域,在后续文章中将会详细讨论有关它的内容。
每一个委派对象实际上就是一个方法包装器,当方法被调用时,受作用的对象被操作。MulticastDelegate类定义两个只读公共实例属性:Target和Method。给定一个委派对象引用,你就可以查询到它的这些属性。如果方法被回调,Target属性返回一个对将要操作的对象的引用。如果方法是静态的,则Target返回null。Method属性返回标示回调方法的System.Reflection.MethodInfo对象。
你可以用几种方式使用这些信息。一种方式是检查是否某个委派对象引用特定类型的实例方法:
//
Boolean DelegateRefersToInstanceMethodOfType(
MulticastDelegate d, Type type) {
return((d.Target != null) && d.Target.GetType == type);
}
//
你还应该编写代码检查是否回调方法由专门的名字(如FeedbackToMsgBox):
//
Boolean DelegateRefersToMethodOfName(
MulticastDelegate d, String methodName) {
return(d.Method.Name == methodName);
}
//
现在你知道了如何构造委派对象,下面让我们来谈谈回调方法是如何被调用的。为方便起见,我们还是使用
Set类中的ProcessItems:
//
public void ProcessItems(Feedback feedback) {
for (Int32 item = 1; item <= items.Length; item++) {
if (feedback != null) {
// 如果指定任何回调,则调用它们
feedback(items[item], item, items.Length);
}
}
}
//
注释行下面的那一行代码就是调用回调方法。仔细看看代码,它调用feedback函数并传递三个参数。但是feedback是不存在的。再一次指出,编译器知道feedback是个引用某个委派对象的变量,并且编译器会产生实际的代码来调用委派对象的Invoke方法。换句话说,编译器看到下面这行代码后:
feedback(items[item], item, items.Length);
编译器产生的结果与下面这行源代码产生的结果一样:
feedback.Invoke(items[item], item, items.Length);
事实上,通过使用ILDasm.exe程序检查ProcessItems代码结果(如图五),你能发现这一点。
- 发表评论
-
- 最新评论 更多>>