本来准备直接进入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 - 循环和异常的更多相关文章

  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. Android怎么找到最优适配资源

    当我们将一些提供了不同的资源文件可供Android系统选择的时候,Android会在运行时会根据一套适配的规则选择最符合当前配置的资源.为了说明Android怎么选择资源,假设我们有以下可选的资源文件 ...

  2. FB引擎系列-之CloudSand

    CloudSand,欲打破之前的集中版本制作的模式, http://code.taobao.org/p/cloudsand包含服务器端代码(php)和客户端代码(unity)   EasyDown的时 ...

  3. [每日电路图] 1、基于AT89C52单片机最小系统接口电路【转】

              come from:http://www.21ic.com/dianlu/basis/interface/2015-04-21/621607.htm AT89C52是美国Atmel ...

  4. 让C#轻松实现读写锁分离--封装ReaderWriterLockSlim

    ReaderWriterLockSlim 类 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问. 使用 ReaderWriterLockSlim 来保护由多个线程读取但每次只采用一 ...

  5. synchronized同步对象锁

    package com.system.util; import com.common.Constants; import com.util.Cache; /** * 创建同步对象锁 * * @auth ...

  6. IOS Animation-CABasicAnimation、CAKeyframeAnimation详解&区别&联系

    1.先看看网上流传的他们的继承图: 从上面可以看出CABasicAnimation与CAKeyframeAnimation都继承于CAPropertyAnimation.而CAPropertyAnim ...

  7. Redis中统计各种数据大小的方法

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/125.html?1455853369如果 MySQL 数据库比较大的话,我 ...

  8. Atitit 游戏的通常流程 attilax 总结 基于cocos2d api

    Atitit 游戏的通常流程 attilax 总结 基于cocos2d api 加载音效1 加载页面1 添加精灵1 设置随机位置2 移动2 垃圾gc2 点击evt2 爆炸效果3 定时生成精灵3 加载音 ...

  9. 浅谈iOS版本号

    作者:Travis FIR.im 一直在尽量兼容不同使用习惯的版本号形式, 但是在使用中我们发现好多开发者对怎么更好的用版本号来标示应用很陌生. 这是篇基础文章, 简单介绍 iOS 的版本号. 名词解 ...

  10. iOS中的预编译指令的初步探究

    目录 文件包含 #include #include_next #import 宏定义 #define #undef 条件编译 #if #else #endif #if define #ifdef #i ...