使用 Emit 生成 IL 代码
.NET Core/.NET Framework 的 System.Reflection.Emit 命名空间为我们提供了动态生成 IL 代码的能力。利用这项能力,我们能够在运行时生成一段代码/一个方法/一个类/一个程序集。
本文将介绍使用 Emit 生成 IL 代码的方法,以及在此过程中可能遇到的各种问题。
在编写以下代码时如果遇到一些意料之外的错误,希望调试生成的 IL 代码,可以尝试阅读 如何快速编写和调试 Emit 生成 IL 的代码 - walterlv 了解如何调试和解决。
用 Emit 生成 IL 代码时,很多我们写 C# 时不会注意到的问题现在都需要开始留意。
在阅读本文之前,希望统一一个平时可能不太留意的英文:
- 形参:parameter
- 实参:argument
如果不了解它们之间的区别,请自行搜索。
定义方法签名
在 IL 中,方法名称可以使用比 C# 更多的字符,例如“<”和“>”,这也是 C# 编译闭包时喜欢使用的字符。目前我还没有找到 IL 中哪些字符可以作为标识符名称,但从混淆工具来看,是比 C# 多得多的。
如果你试图生成实例方法,那么实例本身 this 将成为第一个参数,不过并不需要额外将它定义到参数列表中。
当然,如果是静态方法,我们能够自己指定一个 this 参数,不过没有实际的意义。
var method = new DynamicMethod("<MethodName>",
typeof(void), new[] { typeof(object), typeof(object) });
method.DefineParameter(1, ParameterAttributes.None, "this");
method.DefineParameter(2, ParameterAttributes.None, "value");
如果不声明形参,那么生成的 IL 代码的函数将无法被正常调用(提示可能造成运行时的不稳定)。
声明和初始化局部变量
平时写 C# 的时候,可能一个方法里面没有定义任何一个局部变量,但 IL 可不一定这么认为。
例如:
int a = 0;
if (value.GetType() == typeof(string))
{
}
else
{
}
实际上,在 IL 中,除了 Int32 类型的 a 之外,还会额外定义一个 bool 类型的局部变量 V_1。在 value.GetType() == typeof(string) 执行完后,其值将存入 V_1。
所以,如果需要编写 Emit 生成代码的代码,需要注意这些隐式产生的局部变量,它们需要和普通变量一样被初始化。
Emit 代码为:
// 这就声明了两个局部变量。
il.DeclareLocal(typeof(int));
il.DeclareLocal(typeof(bool));
定义标签
如果代码中存在非线性结构,例如 if-else,那么 IL 就需要知道跳转的地址。那么如何能够知道跳转到哪个地址呢?
——使用标签。
对 if-else 来说,if 操作需要知道 else 的起始地址;对于 if 内部的结尾来说,需要知道整个 if-else 结束之后的第一个操作的地址。
var startOfElse = il.DefineLabel();
var endOfWholeIfElse = il.DefineLabel();
il.Emit(OpCodes.Nop);
// 其他生成代码。
// 如果 if 条件不满足,跳转到 startOfElse。
il.Emit(OpCodes.Brfalse_S, startOfElse);
// 其他生成代码。
// 在 if 结束之后,跳转到 endOfWholeIfElse 地址。
il.Emit(OpCodes.Br_S, endOfWholeIfElse);
// 其他生成代码。
// 假设这里到了 else 的开头了,于是将 startOfElse 进行标记。标记完紧跟着写 else 部分的代码。
il.MarkLabel(startOfElse);
il.Emit(OpCodes.Nop);
// 其他生成代码。
// 假设这里整个 if-else 结束了,于是将 endOfWholeIfElse 进行标记。
il.MarkLabel(endOfWholeIfElse);
参考资料
- 生成方法签名与元数据
- 生成方法体
使用 Emit 生成 IL 代码的更多相关文章
- 如何快速编写和调试 Emit 生成 IL 的代码
.NET Core/.NET Framework 的 System.Reflection.Emit 命名空间为我们提供了动态生成 IL 代码的能力.利用这项能力,我们能够在运行时生成一段代码/一个方法 ...
- Emit 自动生成IL代码,注入代码
Spring 框架中的注入代码,以及自动生成对接口的实现,则根据il代码注入 Emit学习(1)-Emit概览 一.Emit概述 Emit,可以称为发出或者产生.在Framework中,与Emit相关 ...
- 【抬杠.NET】如何进行IL代码的开发
背景 在有些时候,由于C#的限制,或是追求更高的性能,我们可以编写IL代码来达到我们的目的.本文将介绍几种IL代码开发的几种方式,环境为visual studio 2019 + net5.0 sdk. ...
- 【抬杠.NET】如何进行IL代码的开发(续)
背景 之前写了一篇文 [抬杠.NET]如何进行IL代码的开发 介绍了几种IL代码的开发方式. 创建IL项目 C#项目混合编译IL 使用InlineIL.Fody 使用DynamicMethod(ILG ...
- 如何通过ildasm/ilasm修改assembly的IL代码
原文地址:http://kb.cnblogs.com/page/101162/ 这段时间为跟踪一个Bug而焦头烂额,最后发现是Framework的问题,这让人多少有些绝望.所以到微软论坛提了个帖子,希 ...
- Ngen生成Native代码实战及优缺点分析
先科普一下,.Net是一个用于Windows的托管代码模型,用于高效构建具有视觉上引人注目的用户体验的应用程序.但这个模型生成的代码并非可执行代码,而是由.Net公共语言运行库环境执行的IL代码.所以 ...
- .net postsharp编译时生成的代码?
使用PostSharp进行AOP框架设计:一个简单的原型 AOP已经不是一个什么新名词了,在博客园使用关键字搜索可以查出n多条关于AOP的介绍,这里就不再赘述了. 在Bruce Zhang's B ...
- 一、源代码-面向CLR的编译器-托管模块-(元数据&IL代码)
本文脉络图如下: 1.CLR(Common Language Runtime)公共语言运行时简介 (1).公共语言运行时是一种可由多种编程语言一起使用的"运行时". (2).CLR ...
- 【小白学C#】浅谈.NET中的IL代码
一.前言 前几天群里有位水友提问:”C#中,当一个方法所传入的参数是一个静态字段的时候,程序是直接到静态字段拿数据还是从复制的函数栈中拿数据“.其实很明显,这和方法参数的传递方式有关,如果是引用传递的 ...
随机推荐
- VC中release和debug版本的区别
DEBUG版本 包含调试信息,编译器生成的代码方便调试 RELEASE版本 算是发布版本,RELEASE下不能调试,生成的文件更小,编译器生成的程序速度更快但是Debug下生成的exe文件在单独运行时 ...
- 这真是奇葩的js题目
url:http://javascript-puzzlers.herokuapp.com/ 有兴趣的可以一看,算是比较偏门自我感觉
- Weex了解
weex描述 weex是一个使用web开发体验来开发高性能原生应用的框架,能支持vue.js框架.它可以实现用同一套代码来构建Andriod.IOS和web应用.可以实现使用JavaScript和流行 ...
- Seaborn-05-Pairplot多变量图
转自:http://www.jianshu.com/p/6e18d21a4cad
- spring注入的四种方式
配置文件spring.xml: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=&qu ...
- Exact Change
设计一个收银程序 checkCashRegister() ,其把购买价格(price)作为第一个参数 , 付款金额 (cash)作为第二个参数, 和收银机中零钱 (cid) 作为第三个参数. cid ...
- Linux中jar包指定端口启动并记录日志
Linux中jar包指定端口启动并记录日志: java -jar -Dserver.port=38080 group-buying-0.0.1-SNAPSHOT.jar >log.log ...
- 块级元素display:inline-block 在IE6 IE7无效
ie6,ie7中,对块级元素设置display:inline-block,无效. 所以要先设置为inline,再触发haslayout .div1{ /*重点代码开始*/ display: inlin ...
- SCRF的简介及防护手段
CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造. CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求. 包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购 ...
- New Concept English three(15)
31w/m 43 Children always appreciate small gifts of money. Father, of course, provides a regular supp ...