欢迎来到.net学习网

欢迎联系站长一起更新本网站!QQ:879621940

您当前所在位置:首页 »  .NET本质论第一卷:公共语言运行库教程 » 正文

本教程章节列表

.net本质论第六章-显式方法调用(二)

创建时间:2012年12月27日 18:17  阅读次数:(3158)
分享到:
示例6.8 通过MethodInfo.Invoke显式地调用
Public sealed class Utils
{
Static public int callAdd(object target){
//从对象的类型中抓取”Add”方法
Type type=target.GetType();
MethodInfo method=type.GetMethod(“Add”,BindingFlags.Public| BindingFlags.NonPublic| BindingFlags.Instance);
//检查方法是否存在
If(method==null) return 0;

//形成参数值列表
Object[] args=new object[]{10,230,30};
//执行这个方法
Object result=method.Invoke(target,args);
//返回结果
Return (int)result;
}
}

图6.5展示了MethodInfo对象如何关联底层方法和目标对象。注意有一个底层System.RuntimeMehtodHandle引用,它指向描述该方法的CLR托管数据结构。你可以使用System.RuntimeMethodHandle.GetFunctionPointer方法访问底层方法代码的地址,当找到这个地址后,喜欢使用底层编程技巧的程序员就能够直接调用这个方法,而不用承担MethodInfo.Invoke的开销。

由GetFunctionPointer返回的地址意味着它必须由CIL的calli指令调用。与call和calivirt指令不一样,calli指令直接将目标方法的元数据记号编码到指令流中。在运行时, calli指令所期望的目标方法的地址将被压入到堆栈中。这种间接性允许CLR支持c风格函数指针。例如,假设你有如下的C#类型声明:
Public class Target{
Public static int Addc(int x,int y){return x+y;}
Pulbic int Subtract(int x,int y){return x-y;}
}

你将能编写下面的C++代码:
Using namespace System;
Using namespace System::Reflection;

Typedef int (__fastcall*AddProc)(int,int);
Typedef int (__fastcall*SubProc)(Target*,int ,int);

Void f(Target*pTarget){
//获取方法指针
Type*ptype=pTarget- >GetType();
MethodInfo*padd=ptype- >GetMethod(S’”Add”);
MethodInfo*psub=ptype- > GetMethod(S”Subtract”);
IntPtr pfnAdd=padd- >MethodHandle.GetFunctionPointer();
IntPtr pfnSub=psub- > MethodHandle.GetFunctionPointer();

//调用
Int r1=((AddProc)pfnAdd)(3,4);
Int r2=((SubProc)pfnSub)(pTarget,5,6);
}

遗憾的是,在NET framework l.0版本下,C++编译器的CLR兼容模式(/CLR)并不支持使用_fastcall堆栈规则的函数指针声明,它通常是由CLR内部所使用的规则。尽管构造合适的IA-32机器代码是可能的.C++还是禁止在托管方法中内联程序集。这导致程序员只能使用ILASM编写必要的CIL用于调用函数,除此之外别无选择。这里,ILASM是随.NET framework SDK一起发布的CIL汇编器。

下面的ILASM方法声明展示了如何调用前面例子中所展示的Add方法.
.method public hidebysig static int 32
Call(native int pfn,int32 x,int32 y)cil managed{
.maxstack 3
ldarg.1 //压入x
ldarg.2 //压入y
ldarg.0 //压入目标方法的地址
calli int 32(int 32, int 32)
ret
}

如果c++编译器支持__fastcall函数指针,则这个方法产生的机器代码将与c++函数指针产生的机器代码相同。

为了调用实例方法Subtract,你可以使用这个ILASM方法
.method public hidebysig static int 32
Call(native int pfn,object pThis,int32 x,int32 y)cil managed{
.maxstack 4
ldarg.1 //压入pThis.
ldarg.2 //压入x
ldarg.3 //压入y
ldarg.0 //压入目标方法的地址
calli int 32(object, int 32, int 32)
ret
}

在这两种情形下,Call的第一个参数都是一个由MethodBase.GatFunctionPointer所返回的函数指针。注意,在这两个例子中很重要的是,当JIT编译器把这个CIL翻译成机器代码时.似乎每个参数都被传递到堆栈,但是根据__fistcall的调用约定,前两个参数将被传递到ecx和
edx寄存器。W嶯C
来源:.net学习网
说明:所有来源为 .net学习网的文章均为原创,如有转载,请在转载处标注本页地址,谢谢!
【编辑:Wyf】

打赏

取消

感谢您的支持,我会做的更好!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

最新评论

共有评论0条
  • 暂无任何评论,请留下您对本文章的看法,共同参入讨论!
发表评论:
留言人:
内  容:
请输入问题 29+54=? 的结果(结果是:83)
结  果: