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 ...
随机推荐
- 一致性hash的理解
参考: http://www.blogjava.net/hello-yun/archive/2012/10/10/389289.html http://blog.csdn.net/cywosp/art ...
- 消息中间件与JMS标准
初识消息中间件 维基百科上对于消息中间件的定义是"Message-oriented middleware(MOM) is software infrastructure focused on ...
- dijit样式定制(二)dijit.form.Select与dijit.form.NumberSpinner
dijit.form.Select: Select的样式位于Claro/form/Select.less中,Select主要通过table来布局,下图可以看到Select的布局结构 介绍几个主要的cl ...
- 像素图的实时光照 Lighting on Pixel Art
去年有这样一个工具,We got one toolkit last year. 他有什么功能呢?What is its function? 让你画出各个方向的照明图 That you can draw ...
- ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇
在之前的文章中,我为大家介绍了OWIN和Katana,有了对它们的基本了解后,才能更好的去学习ASP.NET Identity,因为它已经对OWIN 有了良好的集成. 在这篇文章中,我主要关注ASP. ...
- [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之灯光介绍Lights
[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之灯光介绍Lights 既上一篇分享了中文字幕的摄像机介绍Cameras后,本篇分享一下第2个已完工的 ...
- ASP.NET中一种超简单的Ajax解决方案
为什么是Ajax2? 因为之前有一个blqw.Ajax,并且已经在项目中投入使用了,但是没有这个方便,这个是后来才弄的,为了纪念第一版的blqw.Ajax,所以这个就2了... 话说看了评论才发现,原 ...
- 看stackoverflow大牛如何回答何时在ASP.NET中使用异步控制器?
转载自博客园:http://farb.cnblogs.com/ 今天无意中看到stackoverflow上一个很好的问答,个人觉得很有价值,所以翻译过来和大家共享!希望大家能相互交流. 在ASP.NE ...
- Mybatis错误(一)org.apache.ibatis.exceptions.PersistenceException
在映射文件中,通过parameterType指定输入参数的类型,类型可以是简单类型.hashmap.pojo的包装类型.在测试包装类型过程中产生了一个错误:org.apache.ibatis.exce ...
- EF架构~CodeFirst自关联表的插入
回到目录 这个文章对之前EF的一个补充,对于一些自关联表的添加,如果你建立了表约束确实有这种问题,一般主键为整形自增,父ID为可空,这时,在添加时如果不为ID赋值,结果就会出错. 错误: 无法确定依赖 ...