C#如何用IL和Emit类通过Calli来实现实例函数与静态函数的调用霁雪湖上三映月

最近充能看书,在书上看到函数调用可以"通过ldftn获得函数指针,然后使用calli指令"来进行调用,并说这种行为"类似C的函数指针,但是C#不支持这种行为",那么这是一种什么样的调用呢?我翻阅了一些资料,才知道ldftn和calli分别是IL语言中的两个指令,也就是说这是一种基于IL语言的调用。

1.首先我们要实现的方法调用,首先我们有如下类:

(1)Ldftn指令:

-语法:ldftn

-功能:把函数指针加载到由MethodDef或MemberRef类型的所指定的方法上

(2)Calli指令:

-语法:calli

-功能:先从栈上弹出函数指针,再从栈上弹出所有的参数,然后根据指定的方法签名进行间接方法调用。必须是有效的StandAloneSig标记。函数指针必须位于栈顶。如过方法返回数值,那么该数值在调用完成后被压入栈上。

★3.IL调用函数方法的一般流程:

一般在IL中使用方式分为两大类,一种是调用托管函数,另外一种是调用非托管的函数,这里我们暂不考虑对非托管函数的调用。对于托管函数,按照其调用方法是不是要引用一个对象实列,可以分为静态方法和实例方法。

接下来就对这两种类型的方法,分别描述一下IL代码的一般流程。

(1)实例方法:

过程如下:

-通过"newobjinstance构造函数签名"先创建一个实例对象,并将对象从栈顶弹出保存到局部变量

-通过"ldftninstance实例方法签名"来获得函数方法的指针,调用完成后这个指针会被放置于栈顶,同理也将栈顶的函数指针弹出并保存到局部变量

-把实例对象放置到栈顶,由于实例方法要this指向的对象,所以这个对象会作为第一个参数arg.0作为this

-按照函数的调用的参数的顺序,依次将变量放置到栈顶

-把函数的指针放置到栈顶

-通过"calliinstance实例方法签名"来进行函数的调用,调用完成之后会把返回值放置与栈顶,最后把栈顶的返回值弹出并保存使用

(2)静态方法:

静态方法不需要this指向的对象,所以这边也不需要先创建一个对象,过程如下:

-通过"ldftn静态方法签名"来获得函数方法的指针,调用完成后这个指针会被放置于栈顶,将栈顶的函数指针弹出并保存到局部变量

-通过"calli静态方法签名"来进行函数的调用,调用完成之后会把返回值放置与栈顶,最后把栈顶的返回值弹出并保存使用

(3)一个简单的实例调用的例子:

.localsinit(nativeintfnptr)...ldfrnvoid[mscorlib]System.Console::WriteLine(int32)stloc.0//本地变量中存储函数指针...ldc.i412345//加载参数ldloc.0callovoid(int32)...下面我们看一下怎么实现对Test和Test2的调用的,直接上菜...

IL代码如下:

.assemblyexternmscorlib{auto}.assemblyMyTest{}.moduleMyTest.exe.classpublicA{.methodpublicspecialnamevoid.ctor(){ldarg.0callinstancevoid[mscorlib]System.Object::.ctor()ret}.methodpublicvoidTest(int32param_0){ldarg.1callvoid[mscorlib]System.Console::WriteLine(int32)ret}.methodpublicstaticvoidTest2(int32param_0){ldarg.0callvoid[mscorlib]System.Console::WriteLine(int32)ret}}.methodpublicstaticvoidMain(){.entrypoint.locals(classAa,int32v_1)//实例方法调用newobjinstancevoidA::.ctor()stloc.0ldftninstancevoidA::Test(int32)stloc.1ldloc.0ldc.i4120ldloc.1calliinstancevoid(int32)//静态方法调用ldftnvoidA::Test2(int32)stloc.1ldc.i4233ldloc.1callivoid(int32)ret}四.C#用Emit类来实现C#代码:

Typetype=CreateTypeHelper.CreateMethodCallingType();//获得方法MethodInfomethodInfo=type.GetMethod("CalliMethodCall");if(methodInfo!=null){methodInfo.Invoke(null,null);}执行结果:

最后我们验证一下动态生成的类。在代码中,我们创建了一个"MethodCalling.dll"用来保存动态生成的类,里面承载了我们的Emit代码生成的IL代码,如下图:

用ILDasm.exe查看后如下图:

看了一下与我们写的IL代码基本一致,今天对Calli调用函数方法的研究基本成功!

THE END
1.首先其次后面是什么顺序1、顺序是这样的:首先、其次、再次、从次、最后。2、如后还要加的话,就是:首先、其次、再次、从此、最后、另外、除此之外、值得一提的是……3、还可以这样排序:写文章的时候一般会按照“首先,其次,再次,最https://m.edu.iask.sina.com.cn/jy/2UXHLRUkODB.html
2.刺客财经:tianya20161102首先就是一个核心问题:客损是什么?客刺客财经:tianya20161102 首先就是一个核心问题:客损是什么? 客损就是用户亏得越多,交易所的盈利也越多,而交易所需要将盈利的一部分分给拉用户进来的代理或商务。代理能拿到的比例甚至高达80%。客损的「魅力」客损模式比较少出现在其他正规金融领域。比如说股市,普通https://xueqiu.com/5677917391/152474609
3.首先的解释首先的意思汉典“首先”词语的解释“首先”字的解释,成语解释,国语辞典,网络解释https://www.zdic.net/hans/%E9%A6%96%E5%85%88
4.外耳道恶性肿瘤的症状是什么耳道恶性肿瘤有哪些饮食禁忌首先要注意不要让外耳道受到伤害,外耳道也是人体一个非常敏感脆弱的地方,这里的皮肤比较的薄,如果不小心就会导致外耳道受伤,受伤之后得不到及时有效的治疗的话就比较容易发生感染,感染之后就会愈演愈烈造成外耳道疾病恶化,最终导致肿瘤出现,所以要想避免外耳道肿瘤首先要做到尽量不要往外耳道塞东西,特别是小孩子可https://yangsheng.120ask.com/article/293833.html
5.南方周末:冯骥才:这个时代文化的使命首先是抢救南方周末:冯骥才:这个时代文化的使命首先是抢救 “历史文化是一次性的,如果失去,不可能重新恢复,没有就没有了。我们现在留下多少,后人拥有多少。” “这是五千年文明的历史中一次空前的遭遇,一次由农耕文明向工业文明转型期间无法避免的文化遭遇。”冯骥才这样概括他这些年致力奋斗的文化境遇与个人的命运。因此,他的http://news.tju.edu.cn/info/1005/46384.htm