本来准备直接进入Dapper的, 但是昨天初步看了一下, 内容不少, Dapper不愧是一款成熟的框架, 里面对各种情况的考虑, 很实用, 不过这也使得我短时间内看不完, 所以得等几天了.

那就先来看看循环和异常吧, 看IL跳转的时候, 有一个标签, 跳来跳去的, 在OpCodes里面, 也是有对应的实现的.

一、示例

Emit学习 - OpCodes - 循环和异常_抛出异常

public static void Xunhuan(int num)         {             try             {                 int sum = 0;                 if (num < 1)                 {                     throw new Exception("num is less than 1");                 }                 for (int i = 1; i <= num; i++)                 {                     sum += i;                 }                 Console.WriteLine("executed successfully : Sum = " + sum);             }             catch (Exception e)             {                 Console.WriteLine("error happened : " + e.Message);             }         }

Emit学习 - OpCodes - 循环和异常_抛出异常_02

在调用Xunhuan()的时候, 传入小于1的值时, 会抛出异常, 进入异常处理部分, 否则进入循环(此处为了演示, 使用循环, 否则应该使用算法计算结果), 求和. 结果我就不贴了.


二、OpCodes实现

Emit学习 - OpCodes - 循环和异常_异常处理_03

static Action<int> action;         static void Main(string[] args)         {             //定义一个动态方法             var method = new DynamicMethod("Xunhuan", null, new Type[] { typeof(int) });             ILGenerator IL = method.GetILGenerator();              //定义标签             var label1 = IL.DefineLabel();               var xunLabel = IL.DefineLabel();             var endLabel = IL.DefineLabel();              //定义本地变量             var sum = IL.DeclareLocal(typeof(int));             var i = IL.DeclareLocal(typeof(int));              IL.Emit(OpCodes.Ldc_I4_0);             IL.Emit(OpCodes.Stloc_0); //sum = 0              IL.Emit(OpCodes.Ldc_I4_1);             IL.Emit(OpCodes.Stloc_1); // i = 1             IL.Emit(OpCodes.Ldstr, "enter number : num = ");             IL.Emit(OpCodes.Ldarg_0);             //实现方式一 装箱             IL.Emit(OpCodes.Box, typeof(int));   //装箱             IL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(object) }));             IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));              Label tryLabel = IL.BeginExceptionBlock(); //try             IL.Emit(OpCodes.Ldarg_0);  //num             IL.Emit(OpCodes.Ldc_I4_1); // 1             IL.Emit(OpCodes.Bge, label1); //num >= 1 -> label1, 注: try里面的跳转, 不能跳出try语句, 只能在内部                          IL.Emit(OpCodes.Ldstr, "num is less than 1");             IL.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new Type[] { typeof(string) })); //new Exception();             IL.Emit(OpCodes.Throw); //throw              IL.MarkLabel(label1);             IL.Emit(OpCodes.Ldloc_1); //i             IL.Emit(OpCodes.Ldarg_0); //num             IL.Emit(OpCodes.Bgt, xunLabel); // i > num -> endLabel              IL.Emit(OpCodes.Ldloc_0);             IL.Emit(OpCodes.Ldloc_1);             IL.Emit(OpCodes.Add);             IL.Emit(OpCodes.Stloc_0); // sum += i;              IL.Emit(OpCodes.Ldloc_1);             IL.Emit(OpCodes.Ldc_I4_1);             IL.Emit(OpCodes.Add);             IL.Emit(OpCodes.Stloc_1); //i+=1;             IL.Emit(OpCodes.Br_S, label1);              IL.MarkLabel(xunLabel);             IL.Emit(OpCodes.Ldstr, "executed successfully : Sum = ");             IL.Emit(OpCodes.Ldloc_0);             //实现方式二 调用Convert.ToString(int num)方法             IL.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) }));             IL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }));             IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }));              IL.MarkLabel(endLabel);             IL.Emit(OpCodes.Nop);              IL.BeginCatchBlock(typeof(Exception)); //catch             IL.Emit(OpCodes.Callvirt, typeof(Exception).GetMethod("get_Message"));             IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));             IL.EndExceptionBlock(); //end                        IL.Emit(OpCodes.Ret);              action = (Action<int>)method.CreateDelegate(typeof(Action<int>)); //此处通过委托的方式来调动方法, 而不再是保存成dll文件了              Console.WriteLine("-------------正常执行---------------");             action.Invoke(10);             Console.WriteLine("-------------异常执行---------------");             action.Invoke(-10);             Console.ReadKey();         }

Emit学习 - OpCodes - 循环和异常_Dynamic/Proxy/Emit_04

实现的方式并不是唯一的, 我写的这个方法, 并不是最简的. 下面贴出reflector反编译的IL代码, 与我写的这个还是有不少不同的.

Emit学习 - OpCodes - 循环和异常_异常处理_05

.method public hidebysig static void Xunhuan(int32 num) cil managed     {         .maxstack 2         .locals init (             [0] int32 num2,             [1] int32 num3,             [2] class [mscorlib]System.Exception exception,             [3] bool flag)         L_0000: nop          L_0001: nop          L_0002: ldc.i4.0          L_0003: stloc.0          L_0004: ldarg.0          L_0005: ldc.i4.1          L_0006: clt          L_0008: ldc.i4.0          L_0009: ceq          L_000b: stloc.3          L_000c: ldloc.3          L_000d: brtrue.s L_001b         L_000f: nop          L_0010: ldstr "num is less than 1"         L_0015: newobj instance void [mscorlib]System.Exception::.ctor(string)         L_001a: throw          L_001b: ldc.i4.1          L_001c: stloc.1          L_001d: br.s L_0029         L_001f: nop          L_0020: ldloc.0          L_0021: ldloc.1          L_0022: add          L_0023: stloc.0          L_0024: nop          L_0025: ldloc.1          L_0026: ldc.i4.1          L_0027: add          L_0028: stloc.1          L_0029: ldloc.1          L_002a: ldarg.0          L_002b: cgt          L_002d: ldc.i4.0          L_002e: ceq          L_0030: stloc.3          L_0031: ldloc.3          L_0032: brtrue.s L_001f         L_0034: ldstr "executed successfully : Sum = "         L_0039: ldloc.0          L_003a: box int32         L_003f: call string [mscorlib]System.String::Concat(object, object)         L_0044: call void [mscorlib]System.Console::WriteLine(string)         L_0049: nop          L_004a: nop          L_004b: leave.s L_0068         L_004d: stloc.2          L_004e: nop          L_004f: ldstr "error happened : "         L_0054: ldloc.2          L_0055: callvirt instance string [mscorlib]System.Exception::get_Message()         L_005a: call string [mscorlib]System.String::Concat(string, string)         L_005f: call void [mscorlib]System.Console::WriteLine(string)         L_0064: nop          L_0065: nop          L_0066: leave.s L_0068         L_0068: nop          L_0069: ret          .try L_0001 to L_004d catch [mscorlib]System.Exception handler L_004d to L_0068     }

Emit学习 - OpCodes - 循环和异常_Dynamic/Proxy/Emit_06

以前总是懒, 对于新的知识, 都是看看, 看懂就成, 但是在实际写的过程中, 会碰到很多看不会遇到的问题, 编码还真不是看看就能写好的, 好记性不如烂笔头, 还是得自己一行一行敲一下, 才能发现里面的问题.