[CLR via C#]异常和状态管理
当CLR检测到某个正在运行的.NET应用程序处于一种特殊的正常执行顺序被打断的状态时,会生成一个异常对象来表示这个错误,并将此对象在方法调用堆栈中向上传送。如果一个程序引发了一个异常却没有处理,CLR将会中断此进程。
一、异常处理机制
1.基本语法
try
{
//可能引发异常的语句
}
catch(Exception e)
{
//对异常进行处理的语句
}
finally
{
//"无论如何都要执行的语句"
}
2.finally语句块中也可能发生异常,如果这种情况发生,则先前的异常会被抛弃。如下示例
class Program
{
static void Main(string[] args)
{
try
{
Method1();
}
catch (NotSupportedException ex)
{
Console.WriteLine("Main NotSupportedException");
}
} private static void Method1()
{
try
{
Method2();
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine("Method1 IndexOutOfRangeException");
}
} private static void Method2()
{
int[] numbers = new int[]; try
{
for (int i = ; i <= ; i++)
{
Console.WriteLine(numbers[i]);
}
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine("Method2 IndexOutOfRangeException"); throw;
}
finally
{
throw new NotSupportedException("Method2 finally exception");
}
}
}
3.CLR的"两轮遍历"异常处理策略
当应用程序拥有多层嵌套的异常捕获结构时,如果最底层或中间层发生了异常,CLR将优先在引发异常的那一层搜索catch语句块,看看有没有"兼容"此类型异常的处理代码,如果没有,"跳到"上一层去搜索,如果上一层还没有,继续往上搜索,由此直到方法调用堆栈的最顶层。这就是CLR异常处理策略的第一轮遍历:查找合适的异常处理程序。
如果在某一层找到了异常处理程序,注意,CLR并不会马上执行之,而是回到"事故现场",再次进行第二轮遍历,执行所有"中间"层次的finally语句块,然后,执行找到的异常处理程序,最后,再从本层开始一直遍历到最顶层,执行所有的finally语句块。但是有一个问题,如果始终没有找到合适的异常处理程序会怎么样,你试试就知道了。
二、catch的"诱惑"
有的程序员害怕让用户看到异常的出现,于是把所有的异常隐藏起来。这种作法其实是应用了一种"鸵鸟"策略,据说当有危险降临而又无法挣脱时,鸵鸟就会将头插入沙中,欺骗自己安全了。现实应用中不建议采取这样的做法来处理异常。
try
{
//功能代码
}
catch(Eexception ex)
{
//在此处"吃掉"所有异常,没有任何代码进行异常处理
}
三、CLR异常处理机制探秘
1.方法的异常处理表
static void Main(string[] args)
{
try
{
int number = Convert.ToInt32(Console.ReadLine());
}
catch (FormatException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine("finally");
}
}
使用ildasm工具反编译出来的代码框架如下所示:
从上述代码中可知:
C#编程语言中的单层的try.catch.finally结构会被转换为"两层嵌套"的类似结构,CLR通过执行leave指令在IL汇编程序的try、catch和finally指令块间跳转,实现所定义的异常捕获和处理逻辑。
单击ildasm的"view"菜单,取消"expand try/catch"选项,可以看到C#编译器生成的IL代码的真面目。
具体功能代码被统一地放置在方法IL代码的前半部分,而用于实现异常捕获的代码放在方法IL代码的后半部分,称为"异常处理表","ret"指令是两部分的分界线。C#编译器通过在合适的地方插入leave指令使得其在无异常的情况下,永远执行不到异常处理代码。异常处理表中的每一项代表一个异常处理子句,IL汇编程序使用try、catch、handler和finally关键字,配合相应地址对前面的功能代码自然分块。
2.CLR如何捕获并处理异常
CLR获取引发异常的IL指令地址,然后从上到下地扫描异常处理表,取出每个catch子句".try"关键字后面跟着的用于定位"块"的起始和结束地址,判断一下引发异常的IL指令地址是否落入到此地址范围中,如果中,取出".catch"关键字后跟着的异常类型,比对一下是否与抛出的异常类型一致或相兼容,如果这个条件得到满足,CLR取出".handler"后的两个IL地址,"准备"执行这两个地址范畴的IL指令。"扫描并查找相匹配的catch子句"过程,是CLR异常处理流程的第一轮。
当找到了合适的异常处理代码后,CLR再"回到原地",再次扫描引发异常方法所包容的异常处理表,这回CLR关注的不再是catch子句,而是finally子句,如果找到了合适的finally子句,CLR执行finally子句所指令的处理指令。"扫描并查找相匹配的finally子句"过程,是CLR处理异常流程的第二轮。
[CLR via C#]异常和状态管理的更多相关文章
- 读书笔记—CLR via C#异常和状态管理
前言 这本书这几年零零散散读过两三遍了,作为经典书籍,应该重复读反复读,既然我现在开始写博了,我也准备把以前觉得经典的好书重读细读一遍,并且将笔记整理到博客中,好记性不如烂笔头,同时也在写的过程中也可 ...
- 对CLR异常和状态管理的一点理解
一:自己的感悟 今天读到<CLR via C#>的异常和状态管理这一章,作者给出了关于异常处理的诸多建议,里面有一些建议自己深有体会,比如说使用可靠性换取开发效率这一节.之前自己对异常怎么 ...
- 【C#进阶系列】20 异常和状态管理
异常就是指成员没有完成它的名称所宣示的行动. public class Girl { public string Name { get; set; } } public class Troy{ Gir ...
- Vue之状态管理(vuex)与接口调用
Vue之状态管理(vuex)与接口调用 一,介绍与需求 1.1,介绍 1,状态管理(vuex) Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态 ...
- Web前端的状态管理
背景 我相信很多朋友跟我一样,初次听到什么 Flux , Redux , Vuex , 状态管理 的时候是一脸懵逼的.因为在外面之前前端大部分开发的时候,根本没有那么多的概念.自从ReactJS火 ...
- Web前端的状态管理(State Management)
背景 我相信很多朋友跟我一样,初次听到什么Flux, Redux, Vuex,状态管理的时候是一脸懵逼的.因为在外面之前前端大部分开发的时候,根本没有那么多的概念.自从ReactJS火爆后,什么Flu ...
- Mobx-React : 当前适合React的状态管理工具
MobX 简单.可扩展的状态管理 MobX 是由 Mendix.Coinbase.Facebook 开源和众多个人赞助商所赞助的. 安装 安装: npm install mobx ...
- 前端技术之:如何在vuex状态管理action异步调用结束后执行UI中的方法
一.问题的起源 最近在做vue.js项目时,遇到了vuex状态管理action与vue.js方法互相通信.互操作的问题.场景如下图所示: 二.第一种解决方法 例如,我们在页面初始化的时候,需要从服务端 ...
- React的状态管理工具
Mobx-React : 当前最适合React的状态管理工具 MobX 简单.可扩展的状态管理 MobX 是由 Mendix.Coinbase.Facebook 开源和众多个人赞助商 ...
随机推荐
- C语言小程序-基于链表的学生信息管理
程序支持增加.查询.删除.存盘和读取操作 一 程序定义和函数声明 头文件studentsys.h定义如下 /* student management system by list */ #ifndef ...
- linux redhat NFS网络共享搭建
nfs网络共享 测试环境: 服务端:redhat6.7 ip:192.168.1.100 客户端:redhat6.7 ip:192.168.1.110 一.服务端 1.创建共享文件夹 权限666即可 ...
- Java集合——ArrayList源码详解
) ArrayList 实现了RandomAccess, Cloneable, java.io.Serializable三个标记接口,表示它自身支持快速随机访问,克隆,序列化. public clas ...
- 网络流Edmonds-Karp算法入门
今天自习课没事干,看书自学了一下网络流中的EK算法.(求最大流) 设s为源点,t为汇点,C为容量矩阵,F为流量矩阵,f为最大流量. 1.初始化F,f 2.用BFS在残量网络中找到一条从s到t的最短增广 ...
- netty之粘包分包的处理
1.netty在进行字节数组传输的时候,会出现粘包和分包的情况.当个数据还好,如果数据量很大.并且不间断的发送给服务器,这个时候就会出现粘包和分包的情况. 2.简单来说:channelBuffer在接 ...
- MongoDB 安装 增删改查
MongoDB 一 介绍 1.高性能的数据存储解决方案是大多数大型Web应用程序和服务的核心.后端数据库负责存储一切东西,从用户账户的信息到购物车中的商品,以及博客和评论数据等.好的Web应用需要 ...
- ServletContext详解 以及用法
ServletContext,是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放.request,一个用户可有多个:session,一个用户一个:而servletContext,所 ...
- VS2015 更改C++模式
亲爱的小伙伴,有没有发现你们的VS2015装完以后和老江湖们用的不一样了,人家的界面打开是这样的 而你的界面打开是这样的 虽然看是只有一左一右的区别,但是内在确实有好多不一样. 想不想想老江湖一样,拥 ...
- 180623-SpringBoot之logback配置文件
SpringBoot配置logback 项目的日志配置属于比较常见的case了,之前接触和使用的都是Spring结合xml的方式,引入几个依赖,然后写个 logback.xml 配置文件即可,那么在S ...
- Unity Shader学习笔记 - 用UV动画实现沙滩上的泡沫
这个泡沫效果来自远古时代的Unity官方海岛Demo, 原效果直接复制3个材质球在js脚本中做UV动画偏移,这里尝试在shader中做动画并且一个pass中完成: // Upgrade NOTE: r ...