.NET中的异常处理机制(一)
1、异常处理的总体指导思想
学习C#中的异常处理机制,大概要了解以下几点:
- 首先,我们需要知道的事所有具体异常都是继承自System.Exception基类的。
- 其次,要熟悉FCL类库内置好的一些异常,例如:FileNotFoundException。
- 最后,不仅要懂得catch异常还要懂得throw异常
在实际动手写异常处理构造之前,首先要大概猜测一下可能会出现什么异常,既然可能发生异常,就意味着肯定存在着不稳定的因素。例如文件IO、网络IO、数据库操作、跟其他程序的交互(包括跟操作系统的交互)等等。由于.NET平台本身的安全设计,那些仅需要CPU、内存的操作往往不大可能出现异常,例如字符串处理操作。如果连这类操作都出现异常说明CPU或内存出现问题了,那么这是.NET平台能不能正常运行还是一回事呢,在应用中处理异常也就多半没什么用了。
那么为何要catch异常呢?主要有几个方面:对用户友好、隐藏敏感信息(比如数据库连接字符串)、增强稳定性(比如对于某些不稳定的操作catch之后再重试几次)、记录日志以便在不能调试的时候获取异常信息。
其实,大部分开发框架中都内置了最顶层的异常处理事件,例如,WinForm中有Application.ThreadException事件、MVC中可以通过Fitler机制实现,这样的话代码中除非要特殊处理才catch,那些尚未预计到的bug就可以通过异常处理事件捕获,不用到处写try...catch。
在catch之后还要懂的throw异常。考虑下面两种情形:
- 考虑输入验证的场景,例如用户输入的email格式不对,这时底层抛出的异常直接传递给顶层的调用者(即和用户交互的UI层),这样调用者可以拿这些异常信息决定如何告知用户。
- 在向顶层抛到过程中,catch异常之后继续抛。之所以要catch也许是因为又发生了其他异常,然后包装一下将它们都抛出去;也许是需要记录一下日志。
2、实例讲解异常处理
下面让我们以本文的一个例子及《.NET中的异常处理机制(二)》中的一个例子来说明如何处理异常。
为什么要处理异常呢?让我们从一个简单的例子看。从一个文本文件读取数据然后打印到控制台上。
public sealed class Program{public static void Main(){StreamReader streamReader = new StreamReader(@"c:\data.txt");Console.WriteLine(streamReader.ReadToEnd());streamReader.Close();}}
如上图的代码,如果不处理异常,那么程序在运行时就会抛出一个FileNotFoundException,然后跟着一大堆该异常的相关信息。这些异常信息对于开发人员也许不是什么问题,但是对于没有.NET相关背景知识的终端用户来说,这就是大麻烦了,因为用户不理解这些信息,这些信息对他们毫无意义。此外,这些异常信息包含着一些有价值的信息,它也许能被黑客利用然后侵入你的应用。最后,从应用的角度来说,如果抛出的异常未被处理,那么程序中抛出异常的程序下面的代码就不会被执行,这导致一些资源不能被释放。拿本例来说,若在读取data.text文本文件时抛出异常并且未被处理,那么streamReader,Close()就不会被执行。
向终端用户(end user)显示未处理的异常是不好的做法,有以下两方面的原因:
- 异常信息对用户来说通常是晦涩难懂的,实际意义不大
- 异常中包含一些信息,能被其他人用来hack进你的应用
异常实际上是一个继承自System.Exception类的具体子类。System.Exception基类提供了几个有用的属性,这些属性包含了异常的丰富信息。比如,message属性和Stack Trace属性。
现在,让我们用C#提供的构造来捕捉异常。
try
{StreamReader streamReader = new StreamReader(@"c:\data1.txt");Console.WriteLine(streamReader.ReadToEnd());streamReader.Close();
}
catch (Exception ex)
{Console.WriteLine(ex.Message);Console.WriteLine(ex.Source);Console.WriteLine(ex.TargetSite);
}
现在,通过try...catch我们捕捉到了异常,但是由于我们传给catch的是基类异常Exception,那么,我们仅能使用几个属性,由于我们已经知道抛出的是FileNotFoundException,故我们可以进行改进,将Exception改为FileNotFoundException,这样的话,我们在Catch语句块中处理异常时可以利用FileNotFoundException的更多属性(比如FileName属性)来提供更加有意义的异常处理程序。比如,我们将异常的Message和Stack Trace属性记录到日志文件或者数据库为了调试目的。在这之后还需要向用户显示一个有意义的信息。注意这里基类Exception提供的属性被我们拿来做实际的异常处理(即记录备案,方便稍后调试),在这之后我们可以通过具体异常子类(比如FileNotFoundException)提供的更多属性来向用户显示更加有意义的信息。如下面的代码所示。
try
{StreamReader streamReader = new StreamReader(@"c:\data1.txt");Console.WriteLine(streamReader.ReadToEnd());streamReader.Close();
}
catch (FileNotFoundException ex)
{//这里将异常的详细信息记录到数据库或日志文件Console.WriteLine("请检查文件{0}是否存在",ex.FileName);
}
现在让我们将上面的代码做一点变化,如下图所示,
try
{StreamReader streamReader = new StreamReader(@"c:\Test_File\Data1.txt");Console.WriteLine(streamReader.ReadToEnd());streamReader.Close();
}
catch (FileNotFoundException ex)
{//这里将异常的详细信息记录到数据库或日志文件Console.WriteLine("请检查文件{0}是否存在",ex.FileName);
}
这里我们添加上了Test_File路径名,但实际上该目录不存在,那么这时就会抛出DirectoryNotFoundException,由于没有对应的处理程序,那么程序就会终止,由于我们在开发中不可能记住所有的抛出的具体异常的类型名,因此,在这里我们可以这样处理,在FileNotFoundException异常的catch块之后添加捕获基类Exception异常的catch块,这样的话,如果有我们预料之外的任何异常都将在最后一个捕获基类Exception异常的catch块中得到处理。这里,需要注意的是所有的捕获具体异常类型的catch块必须位于捕获基类Exception异常的catch块之前,否则C#编译器将报错。这里最后一个捕获基类Exception异常的catch块之所以能捕获任意子类型异常,正是体现了继承的思想:父类型的引用能指向任何子类型的实例对象。
try
{StreamReader streamReader = new StreamReader(@"c:\Test_File\Data1.txt");Console.WriteLine(streamReader.ReadToEnd());streamReader.Close();
}
catch (FileNotFoundException ex)
{//这里将异常的详细信息记录到数据库或日志文件Console.WriteLine("请检查文件{0}是否存在",ex.FileName);
}
catch(Exception ex)
{Console.WriteLine(ex.Message);
}
让我们来看看为什么需要finally块。上面代码中,如果try块抛出异常,那么streamReader就不能正常关闭,进而造成资源得不到释放。这时候finally块就派上用场了,finally块中的语句无论是否抛出异常均保证得到执行。因此,我们常将一些资源清理的工作放在finally块中。本例中,我们可以将streamReader.Close()放在finally块中。
另外,常有人质疑finally块的作用。他们的理由就是可以将资源清理的工作放在最后一个catch语句块之后,因为无论try块中是否发生异常,最后一个catch块之后的程序代码均会被执行。这种说法是错误的!因为当try块捕获到异常,转到catch块中进行处理时,若在catch块中再次抛出异常且此异常没有设置对应的处理程序,那么程序就会终止,不会执行最后一个catch块之后的任何程序代码。
转载于:https://www.cnblogs.com/lian--ying/p/9236620.html
.NET中的异常处理机制(一)相关推荐
- 【Java面试题】21 Java中的异常处理机制的简单原理和应用。
[Java面试题]21 Java中的异常处理机制的简单原理和应用. 参考文章: (1)[Java面试题]21 Java中的异常处理机制的简单原理和应用. (2)https://www.cnblogs. ...
- SpringMVC框架中的异常处理机制
目录 1. 什么是异常处理? 2. SpringMVC框架中的异常处理机制是什么? 3. SpringMVC框架汇中实现异常处理的实现步骤 4. SpringMVC框架出现异常时候的处理过程 5. ...
- 简述java异常机制处理,简述Java中的异常处理机制
简述机制社会实现史观说和想到科学主义志是值学唯物和剩由空余价发展发表的标>的. 异常是下列线药枝杆不属物的菌一疗分于治. 属于损坏严重的是,处理钻井座的无损井架检查检测V类.底第I,明显变形几项 ...
- Java中的异常处理机制的简单原理和应用
java中Throwable这个类可以被作为异常抛出的类,继承它的分为异常Exception和错误Error. Exception表示程序需要捕捉和处理的的异常; Error表示系统级别的错误和程序无 ...
- 知识点讲解七:Python中的异常处理机制
异常的处理机制 try:result = 4 / 0 except Exception as e:print('输出异常:'+str(e)) else:print("try子句没有异常,输出 ...
- Java中的异常处理机制
一.异常分类 在java中所有的异常对象都派生于Throwable, 在Throwable下一层分为了两个分支, Error 和 Exception: Error 类层次结构描述的是java运行时系 ...
- 9、java中的异常处理机制
Java中的异常(Throwable)分为两类:异常Execption和错误Error. Error,也就是错误,这个是不可避免的,出现的问题使得应用停止,例如:服务器损坏.内存溢出等.在 ...
- c语言c2182是什么错误,C语言中一种更优雅的异常处理机制
上一篇文章对C语言中的goto语句进行了较深入的阐述,实际上goto语句是面向过程与面向结构化程序语言中,进行异常处理编程的最原始的支持形式.后来为了更好地.更方便地支持异常处理编程机制,使得程序员在 ...
- 深入理解java异常处理机制
1. 引子 try-catch-finally恐怕是大家再熟悉不过的语句了,而且感觉用起来也是很简单,逻辑上似乎也是很容易理解.不过,我亲自体验的"教训"告诉我,这个东西可不是想象 ...
- 深入对比数据科学工具箱:Python和R的异常处理机制
概述 异常处理,是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况(即超出程序正常执行流程的某些特殊条件).Python和R作为一门编程语言自然也是有各自的异常处理机制的,异常 ...
最新文章
- Android Intent setAction的使用注意
- 内置函数、匿名函数,递归函数
- 基于C#在WinCE6.0系统SQLCE3.5的安装开发使用
- PHP读取创建txt,doc,xls,pdf类型文件
- 国外知名的开源项目托管网站
- latex 设置pdf的页边距
- Flex 学习笔记 ComboBox内容框宽度
- 违反学校防疫规定,这所211高校两研究生被通报批评!
- cc2530设计性实验代码三
- log4j日志设置error级别以上
- 51单片机c语言脉冲计数实验报告,单片机计数器实验报告.doc
- 金九银十,测试思维面试题最新整理
- thinkadmin 各种回调的使用
- Java回炉之File
- [Go WebSocket] 为什么我选用Go重构Python版本的WebSocket服务?
- android 的函数调用,安卓版在函数内部调用子程序,子程序如何能得到函数过程中得到的变量 _ 按键精灵手机版 - 按键精灵论坛...
- 一个电子发票开票平台的系统架构设计(02)
- 含泪整理最优质楷体字体素材,你想要的这里都有
- android arouter原理和作用,ARouter原理剖析
- kubernetes(k8s) 知识总结(第1期)
热门文章
- d3.js(v5.7)的node与数据匹配(自动匹配扩展函数)
- js 难点之原型理解
- Educational Codeforces Round 51 (Rated for Div. 2) The Shortest Statement
- python 连接数据库 pymysql模块的使用
- Kafka ACL使用实战
- 关于C#窗体程序dataGridView控件的用法
- centos7 安装docker-ce ,最新版本docker,docker阿里云加速
- hibernate的环境配置
- Light oj 1233 - Coin Change (III) (背包优化)
- SDI在自定义的工具栏上添加下拉控件