VB的内置反射

Visual Basic一大吸引人的地方是它支持直接的后期绑定。就是说可以直接在代码里访问那些要到运行时才能确定的对象成员。比如这样一段代码:

 

1 None.gif Dim  f  As   Object   =   New  Form2()
2 None.giff.Show()

 

Object是没有Show方法的,但是这段代码可以正确运行。这个功能让VB有了很强的灵活性,它能够直接操作没有类型库的COM对象,而C#则很麻烦。在COM时代,VB的后期绑定是通过IDispatch实现的,而.NET时代,它是由Reflection实现的。为了揭开VB后期绑定的秘密,后面几篇就来讨论一下后期绑定的实现原理。

首先,对方法的调用是后期绑定最重要的一个环节,因为实现了后期绑定的方法调用,就能实现对属性的访问和对事件的操作,这基本上就是对象操作的全部内容。VB的编译器在发现后期绑定的调用后,会用Microsoft.VisualBasic.CompilerServices中的相关操作类实现后期绑定的方法调用。其中,LateBinding.InternalLateCall是这个操作的桥梁。我们来看看这个方法的实现。

这段代码是我从IL手工翻译来的,因为流行的反编译器都不能正确反编译VB的When语句。这段代码很可能有错,凑合着看吧:


 

 1 None.gif < DebuggerStepThrough(), _
 2 None.gif
 3 None.gifDebuggerHidden() >  _
 4 None.gif
 5 ExpandedBlockStart.gifContractedBlock.gif Friend   Function InternalLateCall() Function InternalLateCall( _
 6InBlock.gif
 7InBlock.gif    ByVal o As Object, _
 8InBlock.gif
 9InBlock.gif    ByVal objType As System.Type, _
10InBlock.gif
11InBlock.gif    ByVal name As String, _
12InBlock.gif
13InBlock.gif    ByVal args() As Object, _
14InBlock.gif
15InBlock.gif    ByVal paramnames() As String, _
16InBlock.gif
17InBlock.gif    ByVal CopyBack() As Boolean, _
18InBlock.gif
19InBlock.gif    ByVal IgnoreReturn As Boolean _
20InBlock.gif
21InBlock.gifAs Object
22InBlock.gif
23InBlock.gif

 

    '以下变量的名字已经被我安我的理解改变过

 

   

  1 None.gif   Dim  binder  As  Microsoft.VisualBasic.CompilerServices.VBBinder
  2 None.gif
  3 None.gif     Dim  flags  As  System.Reflection.BindingFlags
  4 None.gif
  5 None.gif     Dim  result  As   Object
  6 None.gif
  7 None.gif     Dim  correctIReflect  As  System.Reflection.IReflect
  8 None.gif
  9 None.gif     Dim  members()  As  System.Reflection.MemberInfo
 10 None.gif
 11 None.gif     Dim  argNumber  As   Integer
 12 None.gif
 13 None.gif     Dim  firstMember  As  System.Reflection.MemberInfo
 14 None.gif
 15 None.gif     Dim  firstMethodBase  As  System.Reflection.MethodBase
 16 None.gif
 17 None.gif     Dim  params()  As  System.Reflection.ParameterInfo
 18 None.gif
 19 None.gif     Dim  paramsNumber  As   Integer
 20 None.gif
 21 None.gif     Dim  paramsInfo  As  System.Reflection.ParameterInfo
 22 None.gif
 23 None.gif     Dim  paramsAttr()  As   Object
 24 None.gif
 25 None.gif 
 26 None.gif
 27 None.gif     If  IgnoreReturn  Then
 28 None.gif
 29 None.gif        flags  =   & H4015D  Or   & H1000000
 30 None.gif
 31 None.gif     Else
 32 None.gif
 33 None.gif        flags  =   & H4015D
 34 None.gif
 35 None.gif     End   If
 36 None.gif
 37 None.gif 
 38 None.gif
 39 None.gif     If  objType  Is   Nothing   Then
 40 None.gif
 41 None.gif         If  o  Is   Nothing   Then
 42 None.gif
 43 None.gif             Throw  ExceptionUtils.VbMakeException( 91 )
 44 None.gif
 45 None.gif         Else
 46 None.gif
 47 None.gif            objType  =  o. GetType ()
 48 None.gif
 49 None.gif         End   If
 50 None.gif
 51 None.gif     End   If
 52 None.gif
 53 None.gif 
 54 None.gif
 55 None.gif    correctIReflect  =  LateBinding.GetCorrectIReflect(o, objType)
 56 None.gif
 57 None.gif 
 58 None.gif
 59 None.gif     If  objType.IsCOMObject  Then
 60 None.gif
 61 None.gif        LateBinding.CheckForClassExtendingCOMClass(objType)
 62 None.gif
 63 None.gif     End   If
 64 None.gif
 65 None.gif 
 66 None.gif
 67 None.gif     If  name  Is   Nothing   Then
 68 None.gif
 69 None.gif        name  =   " "
 70 None.gif
 71 None.gif      End   If
 72 None.gif
 73 None.gif 
 74 None.gif
 75 None.gif    binder  =   New  VBBinder(CopyBack)
 76 None.gif
 77 None.gif 
 78 None.gif
 79 None.gif     If   Not  objType.IsCOMObject()  Then
 80 None.gif
 81 None.gif         ' 以下代码针对非COM对象
 82 None.gif
 83 None.gif 
 84 None.gif
 85 None.gif         ' 通过Reflection获取指定名称成员
 86 None.gif
 87 None.gif        members  =  _
 88 None.gif
 89 None.gif            LateBinding.GetMethodsByName(correctIReflect, name, flags)
 90 None.gif
 91 None.gif 
 92 None.gif
 93 None.gif         If  members  Is   Nothing   OrElse  members.Length  =   0   Then
 94 None.gif
 95 None.gif 
 96 None.gif
 97 None.gif             Throw   New  System.MissingMemberException( _
 98 None.gif
 99 None.gif                Utils.GetResourceString( _
100 None.gif
101 None.gif                 " MissingMember_MemberNotFoundOnType2 " , _
102 None.gif
103 None.gif                name, _
104 None.gif
105 None.gif                Utils.VBFriendlyName(objType, o)))
106 None.gif
107 None.gif 
108 None.gif
109 None.gif         ElseIf  LateBinding.MemberIsField(members)  Then
110 None.gif
111 None.gif 
112 None.gif
113 None.gif             Throw   New  System.MissingMemberException( _
114 None.gif
115 None.gif                Utils.GetResourceString( _
116 None.gif
117 None.gif                 " ExpressionNotProcedure " , _
118 None.gif
119 None.gif                name, _
120 None.gif
121 None.gif                Utils.VBFriendlyName(objType, o)))
122 None.gif
123 None.gif 
124 None.gif
125 None.gif         End   If
126 None.gif
127 None.gif 
128 None.gif
129 None.gif         If  members.Length  =   1   Then
130 None.gif
131 None.gif             ' member的长度为1,意味着只有一个重载
132 None.gif
133 None.gif             ' 因此下面的代码针对没有别名的情况
134 None.gif
135 None.gif 
136 None.gif
137 None.gif            firstMember  =  members( 0 )
138 None.gif
139 None.gif             If  firstMember.MemberType  =   16   Then
140 None.gif
141 None.gif                 ' 如果该成员是属性,则继续获取“GET”访问器的信息
142 None.gif
143 None.gif 
144 None.gif
145 None.gif                firstMember  =  _
146 None.gif
147 None.gif                     CType (firstMember, _
148 None.gif
149 None.gif                    System.Reflection.PropertyInfo).GetGetMethod()
150 None.gif
151 None.gif 
152 None.gif
153 None.gif                 If  firstMember  Is   Nothing   Then
154 None.gif
155 None.gif 
156 None.gif
157 None.gif                     Throw   New  System.MissingMemberException( _
158 None.gif
159 None.gif                        Utils.GetResourceString( _
160 None.gif
161 None.gif                         " MissingMember_MemberNotFoundOnType2 " , _
162 None.gif
163 None.gif                        name, _
164 None.gif
165 None.gif                        Utils.VBFriendlyName(objType, o)))
166 None.gif
167 None.gif 
168 None.gif
169 None.gif                 End   If
170 None.gif
171 None.gif             End   If
172 None.gif
173 None.gif 
174 None.gif
175 None.gif             ' 将成员确定为方法类型,准备调用
176 None.gif
177 None.gif            firstMethodBase  =   CType (firstMember, System.Reflection.MethodBase)
178 None.gif
179 None.gif            params  =  firstMethodBase.GetParameters()
180 None.gif
181 None.gif 
182 None.gif
183 None.gif            argNumber  =  args.Length
184 None.gif
185 None.gif            paramsNumber  =  params.Length
186 None.gif
187 None.gif 
188 None.gif
189 None.gif             If  argNumber  =  paramsNumber  Then
190 None.gif
191 None.gif                 ' 没有任何缺省参数和参数数组的情况
192 None.gif
193 None.gif 
194 None.gif
195 None.gif                 Return  LateBinding.FastCall( _
196 None.gif
197 None.gif                    o, firstMethodBase, params, _
198 None.gif
199 None.gif                    args, objType, correctIReflect)
200 None.gif
201 None.gif             Else
202 None.gif
203 None.gif                 If  CopyBack  Is   Nothing   Then
204 None.gif
205 None.gif                     If  LateBinding.NoByrefs(params)  Then
206 None.gif
207 None.gif                         ' 没有按引用传递的参数
208 None.gif
209 None.gif                         ' 判断最后一个参数是否是参数数组()
210 None.gif
211 None.gif                        paramsInfo  =  params(paramsNumber  -   1 )
212 None.gif
213 None.gif                         If  paramsInfo.ParameterType. IsArray   Then
214 None.gif
215 None.gif                             ' 通过读取自定义Attribute来判断是否参数数组
216 None.gif
217 None.gif                            paramsAttr  =  paramsInfo.GetCustomAttributes( _
218 None.gif
219 None.gif                                 GetType (System.ParamArrayAttribute),  False )
220 None.gif
221 None.gif 
222 None.gif
223 None.gif                             If   Not  (paramsAttr  Is   Nothing  _
224 None.gif
225 None.gif                                 OrElse  paramsAttr.Length  =   0 Then
226 None.gif
227 None.gif 
228 None.gif
229 None.gif                                 ' 没有参数数组,继续用FastCall
230 None.gif
231 None.gif                                 Return  LateBinding.FastCall( _
232 None.gif
233 None.gif                                    o, firstMethodBase, params, _
234 None.gif
235 None.gif                                    args, objType, correctIReflect)
236 None.gif
237 None.gif                             End   If
238 None.gif
239 None.gif                         Else
240 None.gif
241 None.gif                             ' 没有参数数组,继续用FastCall
242 None.gif
243 None.gif                             Return  LateBinding.FastCall( _
244 None.gif
245 None.gif                                o, firstMethodBase, params, _
246 None.gif
247 None.gif                                args, objType, correctIReflect)
248 None.gif
249 None.gif                         End   If
250 None.gif
251 None.gif                     End   If
252 None.gif
253 None.gif                 End   If
254 None.gif
255 None.gif             End   If
256 None.gif
257 None.gif         End   If
258 None.gif
259 None.gif     End   If
260 None.gif
261 None.gif 
262 None.gif
263 None.gif     ' COM对象、有参数数组、有方法别名或者有ByRef参数需要回送值的情况
264 None.gif
265 None.gif     Try
266 None.gif
267 None.gif         ' 用VBBinder来进行所需的处理
268 None.gif
269 None.gif        result  =  binder.InvokeMember( _
270 None.gif
271 None.gif            name, flags, objType, correctIReflect, o, _
272 None.gif
273 None.gif            args,  Nothing Nothing , paramnames)
274 None.gif
275 None.gif 
276 None.gif
277 None.gif         Exit   Try
278 None.gif
279 None.gif     Catch  misMember  As  System.MissingMemberException
280 None.gif
281 None.gif 
282 None.gif
283 None.gif         Throw  misMember
284 None.gif
285 None.gif 
286 None.gif
287 None.gif     Catch  ex  As  System.Exception When _
288 None.gif
289 None.gif        LateBinding.IsMissingMemberException(ex)
290 None.gif
291 None.gif 
292 None.gif
293 None.gif         Throw   New  System.MissingMemberException( _
294 None.gif
295 None.gif            Utils.GetResourceString( _
296 None.gif
297 None.gif             " MissingMember_MemberNotFoundOnType2 " , _
298 None.gif
299 None.gif            name, _
300 None.gif
301 None.gif            Utils.VBFriendlyName(objType, o)))
302 None.gif
303 None.gif 
304 None.gif
305 None.gif     Catch  targetInv  As  _
306 None.gif
307 None.gif        System.Reflection.TargetInvocationException
308 None.gif
309 None.gif 
310 None.gif
311 None.gif         Throw  targetInv.InnerException
312 None.gif
313 None.gif 
314 None.gif
315 None.gif     End   Try
316 None.gif
317 None.gif 
318 None.gif
319 None.gif     Return  result
320 None.gif
321 None.gif 
322 None.gif
323 None.gif End Function
324 None.gif
325 None.gif

关键部分我加了少量注释。总的来说,这段代码首先分解了传递的参数,通过反射从对象的类型中查找所需的方法。在调用的时候,它建立了一个VBBinder类的对象,VBBinder继承自System.Reflection.Binder类,是一个管理实参和型参结合的类。除了用VBBinder调用以外,我们还能看出,如果符合下列情况,将通过另一个方法LateBinding.FastCall来调用方法:

1、不是COM对象的方法

2、方法没有别名(没有重载)

3、没有使用参数数组和可选参数

4、没有按引用传递和接受返回参数的情况

FastCall运行速度可能要比VBBinder.InvokeMember快,它忽略别名和其它高级的用法。

关于VBBinder和LateBinding的具体实现,我们下次继续讨论。


以上为转载!没有经过作者的允许。特此声明!

转载于:https://www.cnblogs.com/maxxxz/archive/2005/08/14/214928.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值