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

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

一、示例

  1. public static void Xunhuan(int num)
  2. {
  3. try
  4. {
  5. int sum = ;
  6. if (num < )
  7. {
  8. throw new Exception("num is less than 1");
  9. }
  10. for (int i = ; i <= num; i++)
  11. {
  12. sum += i;
  13. }
  14. Console.WriteLine("executed successfully : Sum = " + sum);
  15. }
  16. catch (Exception e)
  17. {
  18. Console.WriteLine("error happened : " + e.Message);
  19. }
  20. }

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

二、OpCodes实现

  1. static Action<int> action;
  2. static void Main(string[] args)
  3. {
  4. //定义一个动态方法
  5. var method = new DynamicMethod("Xunhuan", null, new Type[] { typeof(int) });
  6. ILGenerator IL = method.GetILGenerator();
  7.  
  8. //定义标签
  9. var label1 = IL.DefineLabel();
  10. var xunLabel = IL.DefineLabel();
  11. var endLabel = IL.DefineLabel();
  12.  
  13. //定义本地变量
  14. var sum = IL.DeclareLocal(typeof(int));
  15. var i = IL.DeclareLocal(typeof(int));
  16.  
  17. IL.Emit(OpCodes.Ldc_I4_0);
  18. IL.Emit(OpCodes.Stloc_0); //sum = 0
  19.  
  20. IL.Emit(OpCodes.Ldc_I4_1);
  21. IL.Emit(OpCodes.Stloc_1); // i = 1
  22. IL.Emit(OpCodes.Ldstr, "enter number : num = ");
  23. IL.Emit(OpCodes.Ldarg_0);
  24. //实现方式一 装箱
  25. IL.Emit(OpCodes.Box, typeof(int)); //装箱
  26. IL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(object) }));
  27. IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
  28.  
  29. Label tryLabel = IL.BeginExceptionBlock(); //try
  30. IL.Emit(OpCodes.Ldarg_0); //num
  31. IL.Emit(OpCodes.Ldc_I4_1); //
  32. IL.Emit(OpCodes.Bge, label1); //num >= 1 -> label1, 注: try里面的跳转, 不能跳出try语句, 只能在内部
  33.  
  34. IL.Emit(OpCodes.Ldstr, "num is less than 1");
  35. IL.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new Type[] { typeof(string) })); //new Exception();
  36. IL.Emit(OpCodes.Throw); //throw
  37.  
  38. IL.MarkLabel(label1);
  39. IL.Emit(OpCodes.Ldloc_1); //i
  40. IL.Emit(OpCodes.Ldarg_0); //num
  41. IL.Emit(OpCodes.Bgt, xunLabel); // i > num -> endLabel
  42.  
  43. IL.Emit(OpCodes.Ldloc_0);
  44. IL.Emit(OpCodes.Ldloc_1);
  45. IL.Emit(OpCodes.Add);
  46. IL.Emit(OpCodes.Stloc_0); // sum += i;
  47.  
  48. IL.Emit(OpCodes.Ldloc_1);
  49. IL.Emit(OpCodes.Ldc_I4_1);
  50. IL.Emit(OpCodes.Add);
  51. IL.Emit(OpCodes.Stloc_1); //i+=1;
  52. IL.Emit(OpCodes.Br_S, label1);
  53.  
  54. IL.MarkLabel(xunLabel);
  55. IL.Emit(OpCodes.Ldstr, "executed successfully : Sum = ");
  56. IL.Emit(OpCodes.Ldloc_0);
  57. //实现方式二 调用Convert.ToString(int num)方法
  58. IL.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) }));
  59. IL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }));
  60. IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }));
  61.  
  62. IL.MarkLabel(endLabel);
  63. IL.Emit(OpCodes.Nop);
  64.  
  65. IL.BeginCatchBlock(typeof(Exception)); //catch
  66. IL.Emit(OpCodes.Callvirt, typeof(Exception).GetMethod("get_Message"));
  67. IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
  68. IL.EndExceptionBlock(); //end
  69.  
  70. IL.Emit(OpCodes.Ret);
  71.  
  72. action = (Action<int>)method.CreateDelegate(typeof(Action<int>)); //此处通过委托的方式来调动方法, 而不再是保存成dll文件了
  73.  
  74. Console.WriteLine("-------------正常执行---------------");
  75. action.Invoke();
  76. Console.WriteLine("-------------异常执行---------------");
  77. action.Invoke(-);
  78. Console.ReadKey();
  79. }

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

  1. .method public hidebysig static void Xunhuan(int32 num) cil managed
  2. {
  3. .maxstack
  4. .locals init (
  5. [] int32 num2,
  6. [] int32 num3,
  7. [] class [mscorlib]System.Exception exception,
  8. [] bool flag)
  9. L_0000: nop
  10. L_0001: nop
  11. L_0002: ldc.i4.
  12. L_0003: stloc.
  13. L_0004: ldarg.
  14. L_0005: ldc.i4.
  15. L_0006: clt
  16. L_0008: ldc.i4.
  17. L_0009: ceq
  18. L_000b: stloc.
  19. L_000c: ldloc.
  20. L_000d: brtrue.s L_001b
  21. L_000f: nop
  22. L_0010: ldstr "num is less than 1"
  23. L_0015: newobj instance void [mscorlib]System.Exception::.ctor(string)
  24. L_001a: throw
  25. L_001b: ldc.i4.
  26. L_001c: stloc.
  27. L_001d: br.s L_0029
  28. L_001f: nop
  29. L_0020: ldloc.
  30. L_0021: ldloc.
  31. L_0022: add
  32. L_0023: stloc.
  33. L_0024: nop
  34. L_0025: ldloc.
  35. L_0026: ldc.i4.
  36. L_0027: add
  37. L_0028: stloc.
  38. L_0029: ldloc.
  39. L_002a: ldarg.
  40. L_002b: cgt
  41. L_002d: ldc.i4.
  42. L_002e: ceq
  43. L_0030: stloc.
  44. L_0031: ldloc.
  45. L_0032: brtrue.s L_001f
  46. L_0034: ldstr "executed successfully : Sum = "
  47. L_0039: ldloc.
  48. L_003a: box int32
  49. L_003f: call string [mscorlib]System.String::Concat(object, object)
  50. L_0044: call void [mscorlib]System.Console::WriteLine(string)
  51. L_0049: nop
  52. L_004a: nop
  53. L_004b: leave.s L_0068
  54. L_004d: stloc.
  55. L_004e: nop
  56. L_004f: ldstr "error happened : "
  57. L_0054: ldloc.
  58. L_0055: callvirt instance string [mscorlib]System.Exception::get_Message()
  59. L_005a: call string [mscorlib]System.String::Concat(string, string)
  60. L_005f: call void [mscorlib]System.Console::WriteLine(string)
  61. L_0064: nop
  62. L_0065: nop
  63. L_0066: leave.s L_0068
  64. L_0068: nop
  65. L_0069: ret
  66. .try L_0001 to L_004d catch [mscorlib]System.Exception handler L_004d to L_0068
  67. }

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

Emit学习(3) - OpCodes - 循环和异常的更多相关文章

  1. Emit学习(3) - OpCodes - 动态添加属性、构造函数、方法

    上一篇介绍了 IL 的部分, 基础的部分, 暂时就介绍到那里了, 接下来要进入代码编写阶段了. 今天的主题是 在代码运行的过程中, 去动态的创建类, 属性, 方法. 来源:http://www.cnb ...

  2. System.Reflection.Emit学习

    C#反射发出System.Reflection.Emit学习 分享: 1 一.System.Reflection.Emit概述 Emit,可以称为发出或者产生.与Emit相关的类基本都存在于Syste ...

  3. python入门学习:9.文件和异常

    python入门学习:9.文件和异常 关键点:文件.异常 9.1 从文件中读取数据9.2 写入文件9.3 异常9.4 存储数据 9.1 从文件中读取数据 9.1.1 读取整个文件  首先创建一个pi_ ...

  4. Python学习 Part6:错误和异常

    Python学习 Part6:错误和异常 两种不同类型的错误:语法错误和异常 1. 语法错误 语法错误,也被称作解析错误: >>> while True print('Hello w ...

  5. plsql分支,循环,异常

    pl/sql 分支,循环和异常分支:    DECLARE        BEGIN        END; 循环:loop,while,for    1.LOOP        EXIT WHEN ...

  6. 《python基础教程(第二版)》学习笔记 语句/循环/条件(第5章)

    <python基础教程(第二版)>学习笔记 语句/循环/条件(第5章) print 'AB', 123 ==> AB 123 # 插入了一个空格print 'AB', 'CD' == ...

  7. JavaSE学习笔记(6)---异常

    JavaSE学习笔记(6)---异常 ​ 软件程序在运行过程中,非常可能遇到问题,我们称之为异常,英文是:Exception,意思是例外.遇到这些例外情况,或者叫异常,我们怎么让写的程序做出合理的处理 ...

  8. Emit学习(2) - IL - 常用指令介绍

    学习Emit必不可少的, 会使用到IL中间代码. 初见IL代码, 让我有一种汇编的感觉, 让我想起了, 大学时, 学习8051的汇编语言. 多的就不扯了, 直接进入正题, OpCodes指令集是不是有 ...

  9. Emit学习(1) - HelloWorld

    之前看过Dapper(使用到了Emit), CYQ.Data(另一种思路,没有使用Emit)类的框架之后, 也想自己做一个小框架玩一下, 不过此时能力太过欠缺, 做不了Cyq.Data或者PDF.Ne ...

随机推荐

  1. Web端导出CSV

    前端导出文件大部分还是通过服务器端的方式生成文件,然后传递到客户端.但很多情况下当我们导出CSV时并不需要后端参与,甚至没有后端. 做过WebGIS的同学经常会碰到这种场景,用户的兴趣点数据以csv文 ...

  2. 如何捕获和分析 JavaScript Error

    前端工程师都知道 JavaScript 有基本的异常处理能力.我们可以 throw new Error(),浏览器也会在我们调用 API 出错时抛出异常.但估计绝大多数前端工程师都没考虑过收集这些异常 ...

  3. No resource found that matches the given name 'android:Widget.Material.A解决方案

    1:首先新建空白工作区 2:先import appcompat_v7 appcompat_v7在一个类似这样的地方, C:\mywork\android\android-sdk-windows\ext ...

  4. STSdb,最强纯C#开源NoSQL和虚拟文件系统 4.0 RC2 支持C/S架构

    STSdb是什么 再来说明一下STSdb是什么:STSdb是C#写的开源嵌入式数据库和虚拟文件系统,支持实时索引,性能是同类产品的几倍到几十倍,访问官方网站. 温故知新 之前发了文章<STSdb ...

  5. read links July-14

    1)   http://ruby-hacking-guide.github.io/intro.html It has one part to discuss “Technique to read so ...

  6. 奇怪的BUG

    熟语说“常在河边走,哪能不湿鞋”,在现实中我想说:“代码写多了,总会遇到奇怪的bug”,遇到bug不可怕,可怕的是不自己不知道这么解决,有些bug能当时解决,有些在自己知识水平提高后知道如何解决.还有 ...

  7. Java-继承,多态练习0922-02

    创建如下三个类:(People类中的三个方法分别输出一些信息,ChinaPeople 和AmericanPeople类重写父类的三个方法). 父类: package com.lianxi1; publ ...

  8. 说说设计模式~装饰器模式(Decorator)~多功能消息组件的实现

    返回目录 为何要设计多功能消息组件 之前写过一篇装饰器模式的文章,感觉不够深入,这次的例子是实现项目中遇到的,所以把它拿出来,再写写,之前也写过消息组件的文章,主要采用了策略模式实现的,即每个项目可以 ...

  9. Java程序员的日常 —— 注册工厂的妙用

    注册工厂是一种很常用的框架书写方法,它适合于快速创建相同类型的对象. 举个栗子 比如一个家具工厂,有沙发.椅子.茶几等等,正常的编程模式是这样的: //创建 class 沙发{} class 椅子{} ...

  10. salesforce 零基础学习(二十九)Record Types简单介绍

    在项目中我们可能会遇见这种情况,不同的Profile拥有不同的页面,页面中的PickList标签可能显示不同的值.这个时候,使用Record Types可以很便捷的搞定需求. Record Types ...