Emit学习(3) - OpCodes - 循环和异常
本来准备直接进入Dapper的, 但是昨天初步看了一下, 内容不少, Dapper不愧是一款成熟的框架, 里面对各种情况的考虑, 很实用, 不过这也使得我短时间内看不完, 所以得等几天了.
那就先来看看循环和异常吧, 看IL跳转的时候, 有一个标签, 跳来跳去的, 在OpCodes里面, 也是有对应的实现的.
一、示例
- public static void Xunhuan(int num)
- {
- try
- {
- int sum = ;
- if (num < )
- {
- throw new Exception("num is less than 1");
- }
- for (int i = ; i <= num; i++)
- {
- sum += i;
- }
- Console.WriteLine("executed successfully : Sum = " + sum);
- }
- catch (Exception e)
- {
- Console.WriteLine("error happened : " + e.Message);
- }
- }
在调用Xunhuan()的时候, 传入小于1的值时, 会抛出异常, 进入异常处理部分, 否则进入循环(此处为了演示, 使用循环, 否则应该使用算法计算结果), 求和. 结果我就不贴了.
二、OpCodes实现
- 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); //
- 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();
- Console.WriteLine("-------------异常执行---------------");
- action.Invoke(-);
- Console.ReadKey();
- }
实现的方式并不是唯一的, 我写的这个方法, 并不是最简的. 下面贴出reflector反编译的IL代码, 与我写的这个还是有不少不同的.
- .method public hidebysig static void Xunhuan(int32 num) cil managed
- {
- .maxstack
- .locals init (
- [] int32 num2,
- [] int32 num3,
- [] class [mscorlib]System.Exception exception,
- [] bool flag)
- L_0000: nop
- L_0001: nop
- L_0002: ldc.i4.
- L_0003: stloc.
- L_0004: ldarg.
- L_0005: ldc.i4.
- L_0006: clt
- L_0008: ldc.i4.
- L_0009: ceq
- L_000b: stloc.
- L_000c: ldloc.
- 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.
- L_001c: stloc.
- L_001d: br.s L_0029
- L_001f: nop
- L_0020: ldloc.
- L_0021: ldloc.
- L_0022: add
- L_0023: stloc.
- L_0024: nop
- L_0025: ldloc.
- L_0026: ldc.i4.
- L_0027: add
- L_0028: stloc.
- L_0029: ldloc.
- L_002a: ldarg.
- L_002b: cgt
- L_002d: ldc.i4.
- L_002e: ceq
- L_0030: stloc.
- L_0031: ldloc.
- L_0032: brtrue.s L_001f
- L_0034: ldstr "executed successfully : Sum = "
- L_0039: ldloc.
- 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.
- L_004e: nop
- L_004f: ldstr "error happened : "
- L_0054: ldloc.
- 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学习(3) - OpCodes - 循环和异常的更多相关文章
- Emit学习(3) - OpCodes - 动态添加属性、构造函数、方法
上一篇介绍了 IL 的部分, 基础的部分, 暂时就介绍到那里了, 接下来要进入代码编写阶段了. 今天的主题是 在代码运行的过程中, 去动态的创建类, 属性, 方法. 来源:http://www.cnb ...
- System.Reflection.Emit学习
C#反射发出System.Reflection.Emit学习 分享: 1 一.System.Reflection.Emit概述 Emit,可以称为发出或者产生.与Emit相关的类基本都存在于Syste ...
- python入门学习:9.文件和异常
python入门学习:9.文件和异常 关键点:文件.异常 9.1 从文件中读取数据9.2 写入文件9.3 异常9.4 存储数据 9.1 从文件中读取数据 9.1.1 读取整个文件 首先创建一个pi_ ...
- Python学习 Part6:错误和异常
Python学习 Part6:错误和异常 两种不同类型的错误:语法错误和异常 1. 语法错误 语法错误,也被称作解析错误: >>> while True print('Hello w ...
- plsql分支,循环,异常
pl/sql 分支,循环和异常分支: DECLARE BEGIN END; 循环:loop,while,for 1.LOOP EXIT WHEN ...
- 《python基础教程(第二版)》学习笔记 语句/循环/条件(第5章)
<python基础教程(第二版)>学习笔记 语句/循环/条件(第5章) print 'AB', 123 ==> AB 123 # 插入了一个空格print 'AB', 'CD' == ...
- JavaSE学习笔记(6)---异常
JavaSE学习笔记(6)---异常 软件程序在运行过程中,非常可能遇到问题,我们称之为异常,英文是:Exception,意思是例外.遇到这些例外情况,或者叫异常,我们怎么让写的程序做出合理的处理 ...
- Emit学习(2) - IL - 常用指令介绍
学习Emit必不可少的, 会使用到IL中间代码. 初见IL代码, 让我有一种汇编的感觉, 让我想起了, 大学时, 学习8051的汇编语言. 多的就不扯了, 直接进入正题, OpCodes指令集是不是有 ...
- Emit学习(1) - HelloWorld
之前看过Dapper(使用到了Emit), CYQ.Data(另一种思路,没有使用Emit)类的框架之后, 也想自己做一个小框架玩一下, 不过此时能力太过欠缺, 做不了Cyq.Data或者PDF.Ne ...
随机推荐
- Web端导出CSV
前端导出文件大部分还是通过服务器端的方式生成文件,然后传递到客户端.但很多情况下当我们导出CSV时并不需要后端参与,甚至没有后端. 做过WebGIS的同学经常会碰到这种场景,用户的兴趣点数据以csv文 ...
- 如何捕获和分析 JavaScript Error
前端工程师都知道 JavaScript 有基本的异常处理能力.我们可以 throw new Error(),浏览器也会在我们调用 API 出错时抛出异常.但估计绝大多数前端工程师都没考虑过收集这些异常 ...
- 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 ...
- STSdb,最强纯C#开源NoSQL和虚拟文件系统 4.0 RC2 支持C/S架构
STSdb是什么 再来说明一下STSdb是什么:STSdb是C#写的开源嵌入式数据库和虚拟文件系统,支持实时索引,性能是同类产品的几倍到几十倍,访问官方网站. 温故知新 之前发了文章<STSdb ...
- read links July-14
1) http://ruby-hacking-guide.github.io/intro.html It has one part to discuss “Technique to read so ...
- 奇怪的BUG
熟语说“常在河边走,哪能不湿鞋”,在现实中我想说:“代码写多了,总会遇到奇怪的bug”,遇到bug不可怕,可怕的是不自己不知道这么解决,有些bug能当时解决,有些在自己知识水平提高后知道如何解决.还有 ...
- Java-继承,多态练习0922-02
创建如下三个类:(People类中的三个方法分别输出一些信息,ChinaPeople 和AmericanPeople类重写父类的三个方法). 父类: package com.lianxi1; publ ...
- 说说设计模式~装饰器模式(Decorator)~多功能消息组件的实现
返回目录 为何要设计多功能消息组件 之前写过一篇装饰器模式的文章,感觉不够深入,这次的例子是实现项目中遇到的,所以把它拿出来,再写写,之前也写过消息组件的文章,主要采用了策略模式实现的,即每个项目可以 ...
- Java程序员的日常 —— 注册工厂的妙用
注册工厂是一种很常用的框架书写方法,它适合于快速创建相同类型的对象. 举个栗子 比如一个家具工厂,有沙发.椅子.茶几等等,正常的编程模式是这样的: //创建 class 沙发{} class 椅子{} ...
- salesforce 零基础学习(二十九)Record Types简单介绍
在项目中我们可能会遇见这种情况,不同的Profile拥有不同的页面,页面中的PickList标签可能显示不同的值.这个时候,使用Record Types可以很便捷的搞定需求. Record Types ...