IL初步了解
一、概述:
近来也是在看AOP方面的东西,了解到Emit可以实现。之前对Emit的了解也就是停留在Reflector针对方法反编译出来的部分指令。就用这次机会学习下Emit也用这篇随笔记录下学习的过程。某些我也不了解的地方也希望各位了解的朋友指导下。
学习前可以先了解下Opcodes
二、工具
1、vs2015
2、.NET Reflector 9.0
三、入门示例
1、输出Hello World
C#代码
static void Main(string[] args)
{
Console.WriteLine("Hello world!");
}
反编译获取到的IL代码

Emit实现代码
public void HellowWorld()
{
//定义Hellow方法没有返回值没有参数
DynamicMethod helloWorldMethod = new DynamicMethod("HellowWorld", null, null);
//创建IL,动态生成代码
ILGenerator IL = helloWorldMethod.GetILGenerator();
//将输出推送到堆栈上
IL.Emit(OpCodes.Ldstr, "Hello World!");
//执行Console.WriteLine
IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
//方法结束
IL.Emit(OpCodes.Ret);
HelloWordDelegate Method = (HelloWordDelegate)helloWorldMethod.CreateDelegate(typeof(HelloWordDelegate));
Method();
}
委托调用过程中。如果有参数会提示“操作可能破坏运行时稳定性”。(没弄清楚)
四、构建程序集
1、下面通过构建一个类里面包含两个方法来做实例
public int Add(int a, int b)
{
return a + b;
}
public string AddList(string[] array)
{
string result = string.Empty;
; i < array.Length; i++)
{
result = result + array[i];
}
return result;
}
2、看下两个方法反编译出来的IL代码


下面我们来看看这段IL到底是如何实现的
●L0000到L0009:将string.Empty赋值给自定义变量resultName,加载整数0,L0009跳转到L001b执行
●L001b到L0027:加载1处索引值,加载参数1(静态从0开始),Ldlen将数组数目从0开始推送到堆栈上,对比两个数值的大小,(将对比结果存储到索引2处,然后再取出(这步实现中可省略)),然后跳转L_000b执行
●L000b到L001a:加载0处索引值,加载参数1,Ldelem_Ref用来加载string类型元素,执行string.concat方法,将值存储到索引0处,加载索引1处值,加载整数1,两值相加,将值存储到索引0处
●L002a结束返回
3、下面我们通过Emit代码来实现
public void GenerateAssembly()
{
string name = "IL.Dynamic";
string fileName = string.Format("{0}.dll", name);
//构建程序集
AssemblyName assemblyName = new AssemblyName(name);
//应用程序集域
AppDomain domain = AppDomain.CurrentDomain;
//实例化一个AssemblyBuilder对象来实现动态程序集的构建
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
//定义模块(不加filename为瞬态模块,不持久)
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(name);
//定义类型
TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public);
//定义一个Add方法进行简单的相加
MethodBuilder methodBuilder = typeBuilder.DefineMethod("Add", MethodAttributes.Public, typeof(Int32), new Type[] { typeof(int), typeof(int) });
//IL实现
ILGenerator IL = methodBuilder.GetILGenerator();
IL.Emit(OpCodes.Ldarg_1);
IL.Emit(OpCodes.Ldarg_2);
IL.Emit(OpCodes.Add);
IL.Emit(OpCodes.Ret);
//定义一个AddList字符串用for拼接方法
MethodBuilder method2Builder = typeBuilder.DefineMethod("AddList", MethodAttributes.Public| MethodAttributes.Static, typeof(string), new Type[] { typeof(string[]) });
FieldBuilder fieldName = typeBuilder.DefineField("resultName", typeof(string), FieldAttributes.Private | FieldAttributes.Static);
ILGenerator addIL = method2Builder.GetILGenerator();
//用来保存求和结果的局部变量
LocalBuilder resultStr = addIL.DeclareLocal(typeof(String));
////循环中使用的局部变量
LocalBuilder i = addIL.DeclareLocal(typeof(Int32));
Label concatLabel = addIL.DefineLabel();
Label LoopLabel = addIL.DefineLabel();
//设置string result = string.Empty;
addIL.Emit(OpCodes.Ldsfld, fieldName);
addIL.Emit(OpCodes.Stloc_0);
//设置i=0
addIL.Emit(OpCodes.Ldc_I4_0);
addIL.Emit(OpCodes.Stloc_1);
addIL.Emit(OpCodes.Br, concatLabel);
//进入循环体
addIL.MarkLabel(LoopLabel);
addIL.Emit(OpCodes.Ldloc_0);
//参数指定静态从0开始
addIL.Emit(OpCodes.Ldarg_0);
addIL.Emit(OpCodes.Ldloc_1);
//Ldelem_Ref用来加载string 类型元素
addIL.Emit(OpCodes.Ldelem_Ref);
addIL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }));
addIL.Emit(OpCodes.Stloc_0);
addIL.Emit(OpCodes.Ldloc_1);
//i++
addIL.Emit(OpCodes.Ldc_I4_1);
addIL.Emit(OpCodes.Add);
addIL.Emit(OpCodes.Stloc_1);
addIL.MarkLabel(concatLabel);
addIL.Emit(OpCodes.Ldloc_1);
addIL.Emit(OpCodes.Ldarg_0);
addIL.Emit(OpCodes.Ldlen);
addIL.Emit(OpCodes.Conv_I4);
//Clt比较两值大小
addIL.Emit(OpCodes.Clt);
addIL.Emit(OpCodes.Brtrue_S, LoopLabel);
addIL.Emit(OpCodes.Ldloc_0);
addIL.Emit(OpCodes.Ret);
Type type = typeBuilder.CreateType();
assemblyBuilder.Save(fileName);
, , , };
string[] array = new string[] { "a", "b", "c" };
object ob = Activator.CreateInstance(type);
, });
var result1 = type.GetMethod("AddList").Invoke(ob, new object[] { array });
}
3.1、AssemblyBuilderAccess
| Run | 可以执行但不能保存 |
| Save | 保存但不能执行 |
| RunAndSave | 可以执行并保存 |
| ReflectionOnly | 只反射上下文中加载 |
4、运行输出
4.1、生成文件

借助工具反编译查看IL生成的C#代码

4.2、运行结果

通过这个实例对IL可以有了比较基础的了解,在之后的学习中再慢慢喝大家进行交流。项目下载System.IL
IL初步了解的更多相关文章
- 动手写IL到Lua的翻译器——准备
文章里的代码粘过来的时候格式有点问题,原因是一开始文章是在订阅号上写的(gamedev101,文末有二维码),不知道为啥贴过来就没了格式,还要手动删行号,就没搞了. 介绍下问题背景: 小说君正在参与的 ...
- Ecma335、CLR、CLI、CTS、 IL、.net 以及他们之间的关系
以上是个人对他们直接关系的理解:图片是原创 CLI 通用语言基础架构(Common Language Infrastructure), CLI是一个开放型的技术规范,它定义了一个语言无关的跨体系结构的 ...
- 移动端之Android开发的几种方式的初步体验
目前越来越多的移动端混合开发方式,下面列举的大多数我都略微的尝试过,就初步的认识写个简单的心得: 开发方式 开发环境 是否需要AndroidSDK 支持跨平台 开发语言&技能 MUI Win+ ...
- IL异常处理
异常处理在程序中也算是比较重要的一部分了,IL异常处理在C#里面实现会用到一些新的方法 1.BeginExceptionBlock:异常块代码开始,相当于try,但是感觉又不太像 2.EndExcep ...
- CSharpGL(29)初步封装Texture和Framebuffer
+BIT祝威+悄悄在此留下版了个权的信息说: CSharpGL(29)初步封装Texture和Framebuffer +BIT祝威+悄悄在此留下版了个权的信息说: Texture和Framebuffe ...
- Android自定义View初步
经过上一篇的介绍,大家对于自定义View一定有了一定的认识,接下来我们就以实现一个图片下显示文字的自定义View来练习一下.废话不多说,下面进入我们的正题,首先看一下我们的思路,1.我们需要通过在va ...
- 初步认识Node 之Node为何物
很多人即便是在使用了Node之后也不知道它到底是什么,阅读完本文你应该会有一个初步的.具体的概念了. Node的目标 提供一种简单的构建可伸缩网络程序的方法.那么,什么是可伸缩网络程序呢?可伸缩 ...
- [入门级] 基于 visual studio 2010 mvc4 的图书管理系统开发初步 (二)
[入门级] 基于 visual studio 2010 mvc4 的图书管理系统开发初步 (二) Date 周六 10 一月 2015 By 钟谢伟 Category website develop ...
- CLR via C# 摘要二:IL速记
最简单的IL程序 .assembly test {} .method void Func() { .entrypoint ldstr "hello world" call void ...
随机推荐
- 12、Struts2表单重复提交
什么是表单重复提交 表单的重复提交: 若刷新表单页面, 再提交表单不算重复提交. 在不刷新表单页面的前提下: 多次点击提交按钮 已经提交成功, 按 "回退" 之后, 再点击 &qu ...
- 异步 HttpContext.Current 为空null 另一种解决方法
1.场景 在导入通讯录过程中,把导入的失败.成功的号码数进行统计,然后保存到session中,客户端通过轮询显示状态. 在实现过程中,使用的async调用方法,出现HttpContext.Curren ...
- [转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法
一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBo ...
- jquery实现下拉框多选
一.说明 本文是利用EasyUI实现下拉框多选功能,在ComboxTree其原有的基础上对样式进行了改进,样式表已上传demo,代码如下 二.代码 <!DOCTYPE html PUBLIC & ...
- form表单验证-Javascript
Form表单验证: js基础考试内容,form表单验证,正则表达式,blur事件,自动获取数组,以及css布局样式,动态清除等.完整代码如下: <!DOCTYPE html PUBLIC &qu ...
- 【教程】SQLite数据库修复
SQLite 大家都知道,就不多说了. 有时候数据量大了,或者存储过程中出现异常,数据库就可能会出问题. 这是以前公司产品出现过的问题,导致软件都打不开了,我花了不少时间才解决的,趁现在有空贡献出来. ...
- 端盘子的服务生到月薪一万五的IT精英,你能相信吗
一直以来,我都觉得自己不是一个有故事的人. 以前的我,是个乖宝宝,对父母言听计从,特别内向,甚至一度感觉到自卑.不上学之后,我干过送货员,去工地除泥搬砖,当过油漆工,去过工厂,还去饭店当过端盘子的服务 ...
- hive
Hive Documentation https://cwiki.apache.org/confluence/display/Hive/Home 2016-12-22 14:52:41 ANTLR ...
- 纯JS打造比QQ空间更强大的图片浏览器-支持拖拽、缩放、过滤、缩略图等
在线演示地址(打开网页后,点击商家图册): http://www.sport7.cn/cc/jiangnan/football5.html 先看一看效果图: 该图片浏览器实现的功能如下: 1. 鼠标滚 ...
- .Net 4.5可执行程序OutOfMemory
原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com 产线上新部署的服务,发生几次无故停止的情况,通过系统事件看到是这样: 这个服务缓存了大量的数据,内存占用比 ...