.NET(C#):分析IL中的if-else,while和for语句并用Emit实现
这是一篇关于IL和反射Emit的文章(所以不喜欢IL或者Emit的就没必要往下看了),要求读者对IL和Emit工作原理较了解。所有分析IL均在Visual Studio 2010 SP1下编译生成。(其他编译器不一定100%结果一样但逻辑上肯定是等价的,希望读者学到“为什么”,而不是“是什么”)。
分析if-else
C#中的if-else:
if (条件)
//为true代码
else
//为false代码
if-else的IL执行逻辑:
条件为真:goto 真
假
//false代码
goto 退出
真
//true代码
退出
来分析一个示例程序:
C#:
static void doo(bool b)
{
if(b)
Console.WriteLine(1);
else
Console.WriteLine(2);
}
IL:
.maxstack 2
.locals init (
[0] bool CS$4$0000)
L_0000: nop
L_0001: ldarg.0 //b进栈
L_0002: ldc.i4.0 //0(false)进栈
L_0003: ceq //比较b和false
L_0005: stloc.0 //将结果赋值给临时bool
L_0006: ldloc.0 //加载bool
L_0007: brtrue.s L_0012 //如果false,跳至L_0012
L_0009: ldc.i4.1 //true代码
L_000a: call void [mscorlib]System.Console::WriteLine(int32)
L_000f: nop
L_0010: br.s L_0019 //跳至返回
L_0012: ldc.i4.2 //false代码
L_0013: call void [mscorlib]System.Console::WriteLine(int32)
L_0018: nop
L_0019: ret //返回
Emit创建if-else动态方法
有了上面的知识,就可以自己创建一个有if-else语句的动态方法,比如这样一个方法:
static void test(bool b)
{
if(b)
Console.WriteLine("真");
else
Console.WriteLine("假");
}
使用反射Emit创建并运行,代码:
//+ using System.Reflection;
//+ using System.Reflection.Emit;
static void Main(string[] args)
{
//创建DynamicMethod对象
var dm = GetIfElse(); //测试
dm.Invoke(null, new object[] { true });
dm.Invoke(null, new object[] { false });
} static DynamicMethod GetIfElse()
{
var dm = new DynamicMethod("", null, new Type[] { typeof(bool) });
var gen = dm.GetILGenerator(); Label lbFalse = gen.DefineLabel();
Label lbRet = gen.DefineLabel(); //判断
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldc_I4, 1);
gen.Emit(OpCodes.Ceq);
//如果false: 跳至false代码
gen.Emit(OpCodes.Brfalse, lbFalse);
//true代码
gen.EmitWriteLine("真");
//跳至退出
gen.Emit(OpCodes.Br, lbRet);
//false代码
gen.MarkLabel(lbFalse);
gen.EmitWriteLine("假");
//退出代码
gen.MarkLabel(lbRet);
gen.Emit(OpCodes.Ret); return dm;
}
输出:
真
假
OK!
分析while
C#中的while:
while (条件)
{
//true代码
}
IL中while执行逻辑:
goto 判断
真
//true代码
判断
条件为真:goto 真
分析代码,C#:
static void doo(bool b)
{
while (b)
{
Console.WriteLine("TRUE");
}
}
IL:
.maxstack 1
.locals init (
[0] bool CS$4$0000)
L_0000: nop
L_0001: br.s L_0010 //跳至判断
L_0003: nop //true代码
L_0004: ldstr "TRUE"
L_0009: call void [mscorlib]System.Console::WriteLine(string)
L_000e: nop
L_000f: nop
L_0010: ldarg.0 //开始判断,载入b
L_0011: stloc.0
L_0012: ldloc.0 //将b的值赋予临时变量
L_0013: brtrue.s L_0003 //如果为true,跳至true代码
L_0015: ret
Emit创建while动态方法
上面懂了的话,创建一个while循环就非常简单了,我们将动态创建这样一个方法:
static void test(bool b)
{
if(b)
Console.WriteLine("TRUE");
}
代码:
//+ using System.Reflection;
//+ using System.Reflection.Emit;
static void Main(string[] args)
{
//创建DynamicMethod对象
var dm = GetWhile(); //测试
dm.Invoke(null, new object[] { false });
Console.WriteLine("参数false,结束,等待3秒后运行参数true");
System.Threading.Thread.Sleep(3000);
dm.Invoke(null, new object[] { true });
} static DynamicMethod GetWhile()
{
var dm = new DynamicMethod("", null, new Type[] { typeof(bool) });
var gen = dm.GetILGenerator(); Label lbCondition = gen.DefineLabel();
Label lbTrue = gen.DefineLabel(); //跳至判断
gen.Emit(OpCodes.Br, lbCondition); //标记True代码
gen.MarkLabel(lbTrue); gen.EmitWriteLine("TRUE"); //标记判断代码
gen.MarkLabel(lbCondition);
//判断
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldc_I4, 1);
gen.Emit(OpCodes.Ceq);
//如果True,跳至true代码
gen.Emit(OpCodes.Brtrue, lbTrue); gen.Emit(OpCodes.Ret);
return dm;
}
程序输出,当然false参数没有任何输出,然后等3秒后,无限输出TRUE
参数false,结束,等待3秒后运行参数true
TRUE
TRUE
TRUE
TRUE
...
分析for
C#中的for
for (定义; 判断; 追加动作)
{
//动作
}
IL中for执行逻辑:
goto 判断
动作
追加动作 判断
条件为真:goto 动作
呵呵,看似略复杂的for循环其实也是很简单的。
分析代码:
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
IL:
.maxstack 2
.locals init (
[0] int32 i,
[1] bool CS$4$0000)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.0 //i=0
L_0003: br.s L_0012 //跳至判断
L_0005: nop //true代码
L_0006: ldloc.0 //动作代码
L_0007: call void [mscorlib]System.Console::WriteLine(int32)
L_000c: nop //动作代码结束
L_000d: nop //追加动作代码
L_000e: ldloc.0 //i++
L_000f: ldc.i4.1
L_0010: add
L_0011: stloc.0 //更新i,追加动作代码结束
L_0012: ldloc.0 //判断代码
L_0013: ldc.i4.s 10 //10进栈
L_0015: clt //<=判断指令,判断i是否小于10
L_0017: stloc.1
L_0018: ldloc.1 //将结果存入临时本地bool变量
L_0019: brtrue.s L_0005 //如果为true,跳至true代码
L_001b: ret
Emit创建for动态方法
我们将动态创建这样一个方法:
static void test(int c)
{
for (int i = 0; i < c; i++)
{
Console.WriteLine(i);
}
}
代码:
//+ using System.Reflection;
//+ using System.Reflection.Emit;
static void Main(string[] args)
{
//创建DynamicMethod对象
var dm = GetFor(); //测试
dm.Invoke(null, new object[] { 3 });
} static DynamicMethod GetFor()
{
var dm = new DynamicMethod("", null, new Type[] { typeof(int) });
var gen = dm.GetILGenerator(); //临时变量i
LocalBuilder locI = gen.DeclareLocal(typeof(int));
Label lbCondition = gen.DefineLabel();
Label lbTrue = gen.DefineLabel(); //i=0
gen.Emit(OpCodes.Ldc_I4_0);
gen.Emit(OpCodes.Stloc, locI); //跳至判断
gen.Emit(OpCodes.Br, lbCondition); //标记True代码
gen.MarkLabel(lbTrue); //Console.WriteLine(i)
gen.Emit(OpCodes.Ldloc, locI);
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) })); //追加代码
//i++
gen.Emit(OpCodes.Ldloc, locI);
gen.Emit(OpCodes.Ldc_I4_1);
gen.Emit(OpCodes.Add);
gen.Emit(OpCodes.Stloc, locI); //判断代码
gen.MarkLabel(lbCondition);
gen.Emit(OpCodes.Ldloc, locI);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Clt);
//如果True,跳至true代码
gen.Emit(OpCodes.Brtrue, lbTrue); gen.Emit(OpCodes.Ret);
return dm;
}
输出:
0
1
2

转自:https://www.mgenware.com/blog/?p=90
.NET(C#):分析IL中的if-else,while和for语句并用Emit实现的更多相关文章
- 通过IL分析C#中的委托、事件、Func、Action、Predicate之间的区别与联系
先说一下个人理解的结论吧: delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类. delegate声明的变量与delegate声明的事件,并没有本质的区别,事件是在dele ...
- 【Win 10 应用开发】分析 URI 中的查询字符串
分析URI中的字符有K种方法(K >= 2),如果查询字符串中的参数比较简单,可以通过子字符串查找的方式来处理:如果查询字符串相对复杂,你可以使用正则表达式来匹配 key1=value1 , ...
- IL中的栈和闪电的Owin推荐
最近几天有幸得到闪电大哥的指点,了解了EMIT和IL中的一些指令.虽然有高射炮打蚊子的说法,但是我相信“二八定律”,80%的功能可以用20%的技术解决,20%的功能只能用80%的技术解决.大哥的博客: ...
- 【吐血推荐】简要分析unity3d中剪不断理还乱的yield
在学习unity3d的时候很容易看到下面这个例子: void Start () { StartCoroutine(Destroy()); } IEnumerator Destroy(){ yield ...
- [转]DllMain中不当操作导致死锁问题的分析——DllMain中要谨慎写代码(完结篇)
在CSDN中发现这篇文章,讲解的比较详细,所以在这里备份一个.原文链接:http://blog.csdn.net/breaksoftware/article/details/8167641 DllMa ...
- 一个使用C#的TPL Dataflow Library的例子:分析文本文件中词频
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:一个使用C#的TPL Dataflow Library的例子:分析文本文件中词频.
- 从虚拟机指令执行的角度分析JAVA中多态的实现原理
从虚拟机指令执行的角度分析JAVA中多态的实现原理 前几天突然被一个"家伙"问了几个问题,其中一个是:JAVA中的多态的实现原理是什么? 我一想,这肯定不是从语法的角度来阐释多态吧 ...
- Linux的nmon监控结果分析文件中网络分析NET
1.首先,使用# ifconfig查看Linux系统中的网卡名称,有的是eth0,有的是em1,以查看结果为准,下图为em1 2.先试试Linux系统中有没有安装ethtool工具,没有的话,下载et ...
- 【Java入门提高篇】Day23 Java容器类详解(六)HashMap源码分析(中)
上一篇中对HashMap中的基本内容做了详细的介绍,解析了其中的get和put方法,想必大家对于HashMap也有了更好的认识,本篇将从了算法的角度,来分析HashMap中的那些函数. HashCod ...
随机推荐
- oracle学习笔记(一)用户管理
--oracle学习第一天 --连接 @后面连接数据库实例,具体连接到那个数据库 conn scott/tiger@MYORA1; --修改密码 passw; --显示用户 show user; -- ...
- mysqlbinlog恢复数据
操作命令: 复制代码代码如下: show binlog events in 'mysql-bin.000016' limit 10; reset master 删除所有的二进制日志flush logs ...
- UI基础视图----UILabel总结
UILabel是UIKit框架中非常常用的视图类,是UIView的子类,是UIWindow,UIImageView等的兄弟类,因为继承自UIView,所以继承了UIView中的属性和方法,大部分都可以 ...
- hdu5323 Solve this interesting problem(爆搜)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Solve this interesting problem Time Limit ...
- 我的django之旅(二)模板和静态文件
我的django之旅(二)模板和静态文件 标签(空格分隔): django 1.为什么要使用模板 在上一篇博文中,提到了HttpReponse,但是HttpReponse只能传送字符串,如果要构建一个 ...
- 解决Sublime-Text-3在ubuntu下中文输入的问题
在ubuntu下使用ST这神器已经一段日子了,但是一直有个纠结的问题,就是中文输入非常坑爹,曾经一段时间,使用inputHelper这个插件来解决, 但是……每次都要按个快捷键,弹出一个小小小框来输入 ...
- Symfony2 Doctrine从现有Database生成Entity(转载自http://blog.it985.com/6809.html)
在我的以前一章Symfony之十分钟入门说了怎样生成数据库,然后设计实体Entity,再同步数据库的表结构,一般我们的顺序都是这样:生成数据库->设计实体Entity->同步数据库表结构. ...
- 手机user agent大全下载 整理发布一批移动设备的user agent【分享】
手机user agent大全下载 整理发布一批移动设备的user agent[分享] 很多人朋友在玩浏览器的时候 或者写软件的时候需要用到 user agent 这个东西 修改这个 可以使自己的浏览器 ...
- Asp.Net MVC3.0 Partial RenderPartial Action RenderAction 区别和用法
本人写的博文不多,专业知识不强,以下纯属于个人笔记.如有不对,还请各路大拿,拍砖指导,谢谢! 区别: 1.Partial 与 RenderPartial 两个方法性质基本一样,只是把一个静态用户控件给 ...
- 挖掘机控制器与复制其MCU程序
最近的时间都浪费在两台小松PW128UU-1上面.旧的一台拆了变速箱,装上去以后就变得换挡不行了.新的一台一直都不行,弄过液压泵以后下部分的行走又出现一时正常一时不动的情况. 先说说概况:PW128U ...