上次说到后期绑定的桥梁方法InternalLateCall将通过以下条件进行判断:
1、不是COM方法
2、方法没有重载
3、传递的形参表和实参表完全匹配
4、如果不匹配,那么没有需要回传的ByRef参数和参数数组
符合上述条件,就采用LateBinding.FastCall来调用方法,否则采用一个VBBinder对象来处理。从这里我们可以看出VBBinder对象在后期绑定调用中能完成的任务,就是:
1、在多种重载中,查找正确的版本。
2、处理形参和实参结合的问题,包括类型转换、可选参数、参数数组等情况。
3、处理调用COM方法的事宜。
VBBinder是继承自Binder的一个类,而Binder是完成上述任务的抽象类。要实现一个Binder,必须重写BindToMethod、BindToField、SelectMethod、SelectProperty 和 ChangeType这四个抽象方法。其中,BindToMethod方法是后期绑定功能的重点。VB在实现的这个方法中,有非常严密而复杂的挑选和判断语句。我在这里就不贴出它的实现了,几乎都是长长的If语句和Select语句。总之,它的功能就是从多种候选的方法中,选出符合和传入参数的正确版本。
另一个重要的实现ChangeType方法,VB是借用内部针对Object类型的转换函数——CTypeHelper来实现的(看来VB为CType定义了很多新的功能)。而通过参数类型表来选择适当方法的SelectMethod,VB则没有实现它。VBBinder还有很多私有的工具方法,如GetDefaultMemberName就是获取表示默认属性的那个成员等等。
接下来我们看看实现方法调用的VBBinder.InvokeMember方法。它主要分成两个部分:
1、COM对象方法的调用。在COM对象方面,InvokeMember是通过调用包含正确信息IReflect对象(这个对象由InternalLateCall传入)的InvokeMember方法来实现调用的。有意思的是这里对COM对象的可选参数提供了支持,也就是说即使是后期绑定调用COM对象,VB便利的可选参数功能仍然得到支持。而在处理ByRef和需要回送参数值的情况时,VB首先通过RemotingServices.IsTransparentProxy来判断对象是否是一个跨越边界访问所用的透明代理。因为跨越边界访问(如Web Service)的方法调用是无法进行参数值回传的,所以对这种情况将自动取消接受参数值回传。此外由于对COM的访问可能会访问到非托管代码,所以,VB在正式调用前用SecurityPermission.Demand方法对调用堆栈中各级方法的权限进行了检查。如果试图通过后期绑定进行不安全的操作,就会抛出异常。
2、托管对象方法的调用。由于托管对象的方法可以重载,可以用缺省参数,还可以用参数数组等,所以这一部分的判断比较复杂。VB首先区分对象的默认属性/方法调用或一般方法调用,这里面判断的工具就是上面提到的工具方法。对于默认方法,VB将获取这个方法的信息,然后按照一般方法调用的步骤继续调用;对于一般方法调用,VB将寻找所有与调用方法同名的成员,然后通过上问提到的BindeToMethod方法找到正确的版本的MethodBase对象。最后,VB通过从该对象中获取的MethodInfo正式用反射调用对象。这中间还包括对静态方法和安全性的检查等复杂操作。
到此为止,一次完整的后期绑定调用操作就结束了,其中经历的复杂过程确实难以想象。我们下次讨论FastCall的实现和关于后期绑定属性操作的内容。
打印 | 张贴于 2004-04-23 12:38:00 | Tag:技术随笔
留言反馈