MSIL实用指南-生成if...else...语句
if...else...语句是非常重要的选择语句,它的生成一般需要ILGenerator的DefineLabel方法和
MarkLabel方法,以及Brtrue_S和Br_S指令。
一、DefineLabel方法
简单调用ILGenerator的DefineLabel方法会得到一个Label结构体。Label结构体没有复杂的功能,
只是简单做一个标签。
实例代码:
Label label1 = ilGenerator.DefineLabel();
二、MarkLabel方法
MarkLabel方法的参数只有一个,就是Label结构体。
用DefineLabel方法得到的Label结构体并没有指定它的位置,为了指定这个标签的位置,必须要调用、
LGenerator的MarkLabel方法。
实例代码:
ilGenerator.MarkLabel(label1);
三、Brtrue_S和Brtrue指令
Brtrue指令的意思是,如果栈上的值是 true 、不为null、或非零值,当前执行顺序则会跳转到指定的标签
上。
Brtrue_S的意思和Brtrue一样,只是它跳转的标签是短格式。
一般一段程序内的标签都没有超过255个,所以都用Brtrue_S指令。
实例代码:
ilGenerator.Emit(OpCodes.Br_S, labelEnd);
四、Br和Br_S指令
Br指令是无条件跳转到指定标签,Br_S指令和它一样,只是跳转标签是短格式的。
和上面一样,一般用Br_S指令
五、生成步骤
public static void Test(bool flag, bool flag2)
{
if (flag)
{
Console.WriteLine("a");
}
else if (flag2)
{
Console.WriteLine("b");
}
else
{
Console.WriteLine("else");
}
}
我们要实现生成上面的代码,需要进行如下步骤。
1.确定label的数量
if...else语句块总会有结束的地方,所以首先要有一个结束标签。
语句块有多少个判断条件,就需要多少个标签;上面有两个逻辑判断条件,所以还要加两个标签。
else语句部分不需要标签。
上面的语句需要三个标签,要先写下声明标签的程序
Label label1 = ilGenerator.DefineLabel();
Label label2 = ilGenerator.DefineLabel();
Label labelEnd = ilGenerator.DefineLabel();
2.生成判断条件
"if"和"else"buf都有判断条件,首先生成它们的判断条件,再生成Brtrue_S指令。
注意它们的判断结果是false才跳转,如果为true不会跳转。if表达式的结果是和
false比较的。
比如第一个if生成是
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ceq);
ilGenerator.Emit(OpCodes.Stloc_0);
ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Brtrue_S, label1);
3.生成条件为true时的语句块
在Brtrue_S时指令后面是条件为true的语句,生成它之后要跳到语句块结束标签,
之后依次给非结束标签指定位置。
例如
ilGenerator.Emit(OpCodes.Ldstr,"a");
ilGenerator.Emit(OpCodes.Call, writeStringLineMethod); ilGenerator.Emit(OpCodes.Br_S, labelEnd);
ilGenerator.MarkLabel(label1);
4.else部分
else是语句块的最后部分,是上面条件都为false才执行的,之后语句块就结束了,所以不需要跳转。
完整的程序如下:
using System;
using System.Reflection;
using System.Reflection.Emit; namespace LX1_ILDemo
{
class Demo23_IfElse
{
static string binaryName = "Demo23_IfElse.exe";
static string namespaceName = "LX1_ILDemo";
static string typeName = "DemoIfElse"; static AssemblyBuilder assemblyBuilder;
static ModuleBuilder moduleBuilder;
static TypeBuilder typeBuilder;
static MethodBuilder mainMethod;
static MethodBuilder testMethod; static void Emit_TestMethod()
{
testMethod = typeBuilder.DefineMethod("Test", MethodAttributes.Public
| MethodAttributes.Static, typeof(void), new Type[] { typeof(bool), typeof(bool) });
ILGenerator ilGenerator = testMethod.GetILGenerator(); Label label1 = ilGenerator.DefineLabel();
Label label2 = ilGenerator.DefineLabel();
Label labelEnd = ilGenerator.DefineLabel();
MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); LocalBuilder local1 = ilGenerator.DeclareLocal(typeof(bool));
//if(a)
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ceq);
ilGenerator.Emit(OpCodes.Stloc_0);
ilGenerator.Emit(OpCodes.Ldloc_0);
ilGenerator.Emit(OpCodes.Brtrue_S, label1);
ilGenerator.Emit(OpCodes.Ldstr,"a");
ilGenerator.Emit(OpCodes.Call, writeStringLineMethod);
ilGenerator.Emit(OpCodes.Br_S, labelEnd);
ilGenerator.MarkLabel(label1);
//else if(b)
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ceq);
ilGenerator.Emit(OpCodes.Stloc_0);
ilGenerator.Emit(OpCodes.Ldloc_0);
ilGenerator.Emit(OpCodes.Brtrue_S, label2);
ilGenerator.Emit(OpCodes.Ldstr, "b");
ilGenerator.Emit(OpCodes.Call, writeStringLineMethod);
ilGenerator.Emit(OpCodes.Br_S, labelEnd);
ilGenerator.MarkLabel(label2);
//else
ilGenerator.Emit(OpCodes.Ldstr, "else");
ilGenerator.Emit(OpCodes.Call, writeStringLineMethod);
ilGenerator.MarkLabel(labelEnd);
ilGenerator.Emit(OpCodes.Ret);
} public static void Generate()
{
InitAssembly();
typeBuilder = moduleBuilder.DefineType(namespaceName + "." + typeName, TypeAttributes.Public); Emit_TestMethod();
GenerateMain(); assemblyBuilder.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication);
SaveAssembly();
Console.WriteLine("生成成功");
} static void GenerateMain()
{
mainMethod = typeBuilder.DefineMethod("Main", MethodAttributes.Public
| MethodAttributes.Static, typeof(void), new Type[] { });
var ilGenerator = mainMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Ldc_I4_0);
ilGenerator.Emit(OpCodes.Call, testMethod); MethodInfo readKeyMethod = typeof(Console).GetMethod("ReadKey", new Type[] { });
ilGenerator.Emit(OpCodes.Call, readKeyMethod);
ilGenerator.Emit(OpCodes.Pop); ilGenerator.Emit(OpCodes.Ret);
} static void InitAssembly()
{
AssemblyName assemblyName = new AssemblyName(namespaceName);
assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, binaryName);
} static void SaveAssembly()
{
Type t = typeBuilder.CreateType(); //完成Type,这是必须的
assemblyBuilder.Save(binaryName);
}
}
}
MSIL实用指南-生成if...else...语句的更多相关文章
- MSIL实用指南-生成索引器
MSIL实用指南-生成索引器 索引器是一种特殊的属性,它有参数的,也有get和set方法,属性名称一般是"Item",并且方法名称一般名称是"get_Item" ...
- MSIL实用指南-生成foreach语句
foreach可以迭代数组或者一个集合对象.foreach语句格式是它的生成步骤是foreach (<成员> in <集合>) <循环体> 一.声明三个变量,loc ...
- MSIL实用指南-生成for语句
for语句格式是这样的for(<初始化语句>;<条件语句>;<自增减语句>) <循环体> 它可以转换为while语句 if(<条件语句>){ ...
- MSIL实用指南-生成while语句
本篇讲解怎样生成while语句.while语句是编程语言中很重要的循环语句,它的结构是while(<表达式>) <语句或语句块> 当表达式的结果为true时就一直执行语句或语句 ...
- MSIL实用指南-生成异常处理
本篇讲解怎么生成异常.C# 异常处理时建立在四个关键词之上的:try.catch.finally 和 throw. 一.异常的抛出抛出异常在C#语言中要使用throw关键字,使用方法是throw &l ...
- MSIL实用指南-生成属性
本篇讲解怎么生成属性,包括get和set方法. 第一步,生成一个字段生成字段用TypeBuilder.DefineField方法.实例代码: FieldBuilder customerNameBldr ...
- MSIL实用指南-生成构造函数
本篇讲解生成构造函数的一些知识,包括创建实例构造函数.静态构造函数.调用父类构造函数. 生成构造函数的方法生成构造函数的方法是TypeBuilder.DefineConstructor(MethodA ...
- MSIL实用指南-生成接口
本篇讲解怎么样生成接口,即interface. 一.创建类型创建一个接口类型依旧用ModuleBuilder的DefineType方法,但是它的第二个参数必须要有TypeAttributes.Inte ...
- MSIL实用指南-生成内部类
生成内部类用TypeBuilder的DefineNestedType方法,得到另一个TypeBuilder.内部类的可访问性都是TypeAttributes的“Nested”开头一些成员.实例代码:y ...
随机推荐
- Hadoop2.x 体系结构和源码编译
体系结构 Hadoop1的核心组成包括HDFS和MapReduce.HDFS和MapReduce的共同点就是他们都是分布式的. HDFS是包括主节点NameNode,只有一个,还有很多从节点DataN ...
- 不能为虚拟电脑 ubuntu 打开一个新任务.
使用virtualbox报错: 不能为虚拟电脑 ubuntu3 打开一个新任务. The virtual machine 'ubuntu3' has terminated unexpectedly d ...
- Problem : 1202 ( The calculation of GPA )
Losers always whine about their best. Winners go home and fuck the prom queen. 很操蛋却非常有意思的题目,注意变量的类型, ...
- python实现一般最小二乘系统辨识方法
问题: 对于一个未知参数的系统,往往需要用到系统辨识的方法,例如对于一个单输入单输出系统: Z(k)+a1*Z(k-1)+a2*Z(k-2)=b1*U(k-1)+b2*U(k-2)+V(k) 其中:V ...
- WordPress中添加自定义评论表情包的方法
先来看看效果: 现在由于WordPress版本更新,再加上WordPress主题也越来越多,而现在的主题一般都是禁用了WordPress自带的评论表情,其实自带 的评论表情也是很丑的,但是以前我们可以 ...
- 关于Eclipse中Ctrl+Alt+Down和Ctrl+Alt+Up不起作用的解决方法
1.其它软件热键冲突,把其它软件的热键修改为其它按键,或者删掉热键 2.Intel显卡快捷键问题 1).你虽然禁用Intel快捷键,但是Intel快捷键仍然是Ctrl+alt+down,还是存在冲突, ...
- 数据模型LP32 ILP32 LP64 LLP64 ILP64
各个C++实现所选择采用的基础类型的大小统称为"数据模型".有四种广泛采用的数据模型: 32 位系统: LP32 或 2/4/4(int 为 16-bit,long 和指针为 32 ...
- 大数运算的算法设计和C++实现
1.背景 工作中遇到过需要进行极大数据的存储和运算的场景,当时使用Python解决了这个问题,在Python中,整数没有位数限制,使用起来很方便.但是当程序主体使用C/C++实现时,就比较麻烦.所以考 ...
- Mycat 配置说明(schema.xml )
Schema.xml 作为 MyCat中重要的配置文件之一,管理着 MyCat的逻辑库.表.分片规则.DataNode以 及DataSource.弄懂这些配置,是正确使用MyCat的前提. schem ...
- 用C#开发的一个通用的地铁换乘查询工具
日常生活中,上班下班坐地铁已经是常事,每当我想去某一个远一点的地方,如果有地铁首选就是地铁,因为方便嘛!每次坐地铁,我们都是凭肉眼去得出我们心中最佳的换乘方案,但是,如果对于线路较少的城市来说,这个方 ...