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 ...
随机推荐
- [Voice communications] 让音乐响起来
本系列文章主要是介绍 Web Audio API 的相关知识,由于该技术还处在 web 草案阶段(很多标准被提出来,至于取舍需要等待稳定版文档来确定,草案阶段的文档很多都会被再次编辑甚至重写.全部删除 ...
- python--批量下载豆瓣图片
溜达豆瓣的时候,发现一些图片,懒得一个一个扒,之前写过c#和python版本的图片下载,因此拿之前的Python代码来改了改,折腾出一个豆瓣版本,方便各位使用 # -*- coding:utf8 -* ...
- 可拖动的DIV
在做WEB UI设计的时候,拖动某个HTML元素已经成为一种不能忽视的用户界面模式,比较典型的应用例子就是Dialog,一个元素是怎么实现拖动的呢?其实原理非常简单,要想实现首先得了解几个基本知识. ...
- 404 Not Found !
MyEclipse中tomcat服务器运行好好的, 却总是报错, 代码没啥问题啊!! 之前都是运行好好的, 难道是我广告不小心改了哪里引起的?于是对比,回退代码,但是结果还是一样的!! 一个简简单单的 ...
- ios UIView sizeToFit sizeThatFits
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 50, 0, 0)]; testLabel.backgroundC ...
- 使用finfo_file()函数检测上传图片的类型
该函数可以检测文件的MIME类型.因为有时候我们只根据文件后缀来判断是不准确的. function getMIME($filename){ $finfo = finfo_open(FILEINFO_M ...
- linux下编译安装curl
linux下编译安装curl 1.下载curl git clone https://github.com/curl/curl.git 2.在curl目录下生成configure文件 ./buldcon ...
- 微软BI 之SSIS 系列 - 使用 SQL Profilling Task (数据探测) 检测数据源数据
开篇介绍 SQL Profilling Task 可能我们很多人都没有在 SSIS 中真正使用过,所以对于这个控件的用法可能也不太了解.那我们换一个讲法,假设我们有这样的一个需求 - 需要对数据库表中 ...
- Script Component 引用package variable
ScriptComponet 的变量分为两种类型,ReadOnly和ReadWrite,使用C#引用这两种类型的变量,有一点不同. 1,创建两个变量 2,将变量传递给script component ...
- Android notification的使用
notification出现在通知栏中的提示,特别是在4.0以后改进了不少,这里讲得都是基于4.0及4.1以后的. 分类: 1.普通Notification 2.大布局Notification 图1 ...