---------------------------------------------------------------------------------------------------
例子 1: 最简单的语句
public void Test1() { Console.WriteLine("aaaa"); }
生成的IL:
.method public hidebysig instance void Test1() cil managed { .maxstack 8 L_0000: nop L_0001: ldstr "aaaa" L_0006: call void [mscorlib]System.Console::WriteLine(string) L_000b: nop L_000c: ret }
使用ILGenerator的Emit方法,改写为
ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldstr, "aaaa"); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ret);
---------------------------------------------------------------------------------------------------
例子 2
public void Test1() { string str = "aaaa"; Console.WriteLine(str); }
生成的IL:
.method public hidebysig instance void Test1() cil managed { .maxstack 1 .locals init ( [0] string str) L_0000: nop L_0001: ldstr "aaaa" L_0006: stloc.0 L_0007: ldloc.0 L_0008: call void [mscorlib]System.Console::WriteLine(string) L_000d: nop L_000e: ret }
使用ILGenerator的Emit方法,改写为:
var str = il.DeclareLocal(typeof(string)); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldstr, "aaaa"); il.Emit(OpCodes.Stloc, str); il.Emit(OpCodes.Ldloc, str); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ret);
---------------------------------------------------------------------------------------------------
例子 3 : 运算
public void PrintCube(int i) { int cube = i * i * i; Console.WriteLine(cube); }
生成的IL:
.method public hidebysig instance void PrintCube(int32 i) cil managed { .maxstack 2 // 在 .locals 部分声明所有的局部变量。 .locals init ( [0] int32 cube) // 第一个名局部变量,int 型,名为 cube。索引从 0 开始。 L_0000: nop // no operation. L_0001: ldarg.1 // load argument 第一个方法参数入栈,比如“3”。索引号 从 1 开始,而不是从 0 开始。 L_0002: ldarg.1 // 再次向堆栈压入第一个方法参数,又一个“3”。 L_0003: mul // multiply 计算堆栈最顶上两个数的乘积 3×3,并把结果入栈,即堆栈最顶部是 9 了。 L_0004: ldarg.1 // 再次压入第一个方法参数“3”。 L_0005: mul // 堆栈最顶上是“3”,第二是“9”,计算 3×9,此时 27 入栈。 L_0006: stloc.0 // pop value from stack to local variable 堆栈最顶上的值“27”出栈, //并被赋给索引位置“0”处的局部变量 cube,即内存中变量 cube 的值为“27”。 L_0007: ldloc.0 // 局部变量 cube 的值“27”入栈。 L_0008: call void [mscorlib]System.Console::WriteLine(int32) // 控制台输出堆栈最顶上的32 位整数“27”。 L_000d: nop // no operation. L_000e: ret // return from method. }
使用ILGenerator的Emit方法,改写为:
ILGenerator il = methodBuilder.GetILGenerator(); var cube = il.DeclareLocal(typeof(int)); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Mul); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Mul); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) })); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ret);
---------------------------------------------------------------------------------------------------
例子 4 : 循环语句
public void SeparateString(string source) { if (source == null) return; int count = source.Length; char c; for (int i = 0; i < count; i++) { c = source[i]; Console.WriteLine(c); } }
生成的IL:
.method public hidebysig instance void SeparateString(string source) cil managed { .maxstack 2 .locals init ( [0] int32 count, [1] char c, [2] int32 i, [3] bool CS$4$0000) // 索引为“3”的这个布尔型局部变量在 C# 代码中并未显式声明,是编译器编译时添加的, //用于保存执行过程中布尔运算的结果,比如比较 source 是否为空时,以及比较 i<count 时。 L_0000: nop L_0001: ldarg.1 // 方法参数 source 的值入栈。 L_0002: ldnull // “空引用”null入栈。 L_0003: ceq // compare equal 比较栈顶的 null 和第二项的 source 是否相等,并 // 把结果 0(false,source 不为空)或 1(true,source 为空)入栈。 L_0005: ldc.i4.0 // 32 位整型数“0”入栈。 L_0006: ceq // 比较栈顶的“0”和堆栈的第二项,第二项可能是“0”,也可能 // 是“1”。比较的结果“1”或“0”入栈。 L_0008: stloc.3 // 栈顶的“1”或“0”出栈,被保存到索引为“3”的局部变量中。 L_0009: ldloc.3 // 执行后,栈顶为“1”(source 不为空)或“0”(source 为空)。 L_000a: brtrue.s L_000e // branch on non-false or non-null 判断栈顶是否 // 为“1”,如果是,跳转到第“IL_000e”行;否则继续往下执行。 L_000c: br.s L_0036 // unconditional branch 当栈顶为“0”时,才会 // 执行到这一行,这一行的执行结果是程序无条件 // 跳转到第“IL_0036”行。 L_000e: ldarg.1 L_000f: callvirt instance int32 [mscorlib]System.String::get_Length() // 对堆栈最顶上的字符串调用其获取长度的实例方法,长度值被入栈。 // “get_Length()”实际是字符串 Length 属性的“get”部分。 L_0014: stloc.0 // 局部变量 count 被赋值为字符串长度。 L_0015: ldc.i4.0 L_0016: stloc.2 // 局部变量 i 被赋值为 0。 L_0017: br.s L_002e // 无条件跳转到第“IL_002e”行。 L_0019: nop L_001a: ldarg.1 L_001b: ldloc.2 L_001c: callvirt instance char [mscorlib]System.String::get_Chars(int32) // source 中索引为 i 处的 char 值入栈。 L_0021: stloc.1 L_0022: ldloc.1 L_0023: call void [mscorlib]System.Console::WriteLine(char) // char 值被输出到控制台 L_0028: nop L_0029: nop L_002a: ldloc.2 // i 值入栈。 L_002b: ldc.i4.1 // 32 位整数 1 入栈。 L_002c: add // i+1 的结果入栈。 L_002d: stloc.2 // i=i+1。 L_002e: ldloc.2 // i 值入栈。 L_002f: ldloc.0 // count 值入栈。 L_0030: clt // compare less than 比较 i<count 是否为真,比较结果入栈。 L_0032: stloc.3 L_0033: ldloc.3 L_0034: brtrue.s L_0019 // 如果 i<count 则跳转到第“IL_0019”行。 L_0036: ret }
---------------------------------------------------------------------------------------------------
例子 5 : 基本类型
public void SayHello(string toWhom) { int i = 1000; double d = 3.1; float f = 4.2F; Console.WriteLine(i); Console.WriteLine(d); Console.WriteLine(f); }
生成的IL:
.method public hidebysig newslot virtual final instance void SayHello(string toWhom) cil managed { .maxstack 1 .locals init ( [0] int32 i, [1] float64 d, [2] float32 f) L_0000: nop L_0001: ldc.i4 1000 L_0002: stloc.0 L_0003: ldc.r8 3.1 L_000c: stloc.1 L_000d: ldc.r4 4.2 L_0012: stloc.2 L_0013: ldloc.0 L_0014: call void [mscorlib]System.Console::WriteLine(int32) L_0019: nop L_001a: ldloc.1 L_001b: call void [mscorlib]System.Console::WriteLine(float64) L_0020: nop L_0021: ldloc.2 L_0022: call void [mscorlib]System.Console::WriteLine(float32) L_0027: nop L_0028: ret }
---------------------------------------------------------------------------------------------------
例子 5 : if语句
int i = 1; if (i > 1) { Console.WriteLine("i > 1"); } else if (i == 1) { Console.WriteLine("i == 1"); } else { Console.WriteLine("i < 1"); }
生成的IL:
.maxstack 2 .locals init ( [0] int32 i, [1] bool CS$4$0000) L_0000: nop L_0001: ldc.i4.1 L_0002: stloc.0 L_0003: ldloc.0 L_0004: ldc.i4.1 L_0005: cgt L_0007: ldc.i4.0 L_0008: ceq L_000a: stloc.1 L_000b: ldloc.1 L_000c: brtrue.s L_001d L_000e: nop L_000f: ldstr "i > 1" L_0014: call void [mscorlib]System.Console::WriteLine(string) L_0019: nop L_001a: nop L_001b: br.s L_0044 L_001d: ldloc.0 L_001e: ldc.i4.1 L_001f: ceq L_0021: ldc.i4.0 L_0022: ceq L_0024: stloc.1 L_0025: ldloc.1 L_0026: brtrue.s L_0037 L_0028: nop L_0029: ldstr "i == 1" L_002e: call void [mscorlib]System.Console::WriteLine(string) L_0033: nop L_0034: nop L_0035: br.s L_0044 L_0037: nop L_0038: ldstr "i < 1" L_003d: call void [mscorlib]System.Console::WriteLine(string) L_0042: nop L_0043: nop L_0044: ret
使用ILGenerator的Emit方法,改写为:
MethodBuilder methodBuilder = typeBuilder.DefineMethod("If", MethodAttributes.Public, typeof(void), null); ILGenerator il = methodBuilder.GetILGenerator(); var i = il.DeclareLocal(typeof(int)); var b = il.DeclareLocal(typeof(bool)); var lblElse = il.DefineLabel(); var lblElse2 = il.DefineLabel(); var lblEnd = il.DefineLabel(); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldc_I4_1); //取整数1,入栈 il.Emit(OpCodes.Stloc, i); //取栈中第一个值,赋值局部变量i il.Emit(OpCodes.Ldloc, i); //局部变量i入栈 il.Emit(OpCodes.Ldc_I4_1); //取整数1,入栈 il.Emit(OpCodes.Cgt); //取栈中前两个值,进行大于比较, //如果第一个值大于第二个值,则将整数值 1 (int32) 入栈;反之,将 0 (int32)入栈。 //此时的值为 1 il.Emit(OpCodes.Ldc_I4_0); //取整数0,入栈 il.Emit(OpCodes.Ceq); //取栈中前两个值,进行等于比较, //如果这两个值相等,则将整数值 1(int32)入栈;否则,将 0 (int32) 入栈 //此时的值为 0 il.Emit(OpCodes.Stloc, b); //取栈中第一个值,赋值局部变量b il.Emit(OpCodes.Ldloc, b); //局部变量b入栈 il.Emit(OpCodes.Brtrue_S, lblElse); //如果为真,控制流转到lblElse标签处,如果为假,继续下一条语句 il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldstr, "i > 1"); //引用字符串 il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //输出字符串 il.Emit(OpCodes.Nop); il.Emit(OpCodes.Br_S, lblEnd); il.MarkLabel(lblElse); //设定标签lblElse il.Emit(OpCodes.Ldloc, i); //局部变量i入栈 il.Emit(OpCodes.Ldc_I4_1); //取整数1,入栈 il.Emit(OpCodes.Ceq); //取栈中前两个值,进行等于比较 il.Emit(OpCodes.Ldc_I4_0); //取整数0,入栈 il.Emit(OpCodes.Ceq); //取栈中前两个值,进行等于比较 il.Emit(OpCodes.Stloc, b); //取栈中第一个值,赋值局部变量b il.Emit(OpCodes.Ldloc, b); //局部变量b入栈 il.Emit(OpCodes.Brtrue_S, lblElse2); //如果为真,控制流转到lblElse2标签处,如果为假,继续下一条语句 il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldstr, "i == 1"); //引用字符串 il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //输出字符串 il.Emit(OpCodes.Nop); il.Emit(OpCodes.Br_S, lblEnd); il.MarkLabel(lblElse2); //设定标签lblElse2 il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldstr, "i < 1"); //引用字符串 il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //输出字符串 il.Emit(OpCodes.Nop); il.MarkLabel(lblEnd); //设定标签lblEnd il.Emit(OpCodes.Ret);
---------------------------------------------------------------------------------------------------
测试完整代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Reflection.Emit; using System.Threading; namespace ILDemo { public class UserInfo { public void Test1() { Console.WriteLine("aaaa"); } /* 各种方法 */ } public class Program { public static void Main(string[] args) { AssemblyName asmName = new AssemblyName(); asmName.Name = "ILDemo"; AssemblyBuilder asmBuilder = Thread.GetDomain().DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave); ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("MyTestDemo"); TypeBuilder typeBuilder = modBuilder.DefineType( "UserInfo", TypeAttributes.Public, typeof(object), null); MethodBuilder methodBuilder = typeBuilder.DefineMethod("Test1", MethodAttributes.Public, typeof(void), null); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldstr, "aaaa"); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ret); /* 各种方法的Emit的实现 */ Type type = typeBuilder.CreateType(); object userInfo = Activator.CreateInstance(type); MethodInfo _MethodInfo = type.GetMethod("Test1"); _MethodInfo.Invoke(userInfo, null); Console.ReadKey(); } } }