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); } } }