异常是指成员没有完成它的名称所宣称的行动。c#
如 FileStream 的 方法里有 Read,Write,等等(行动成员一般用动词表示)。当行动成员不能完成任务时,就应抛出异常。安全
若是代码须要执行通常性的资源清理操做,须要从异常中恢复,或者二者都须要,就能够放到 try 块中。负责清理的代码应该放到一个 finally 块中。try 块还可包含也许会抛出异常的代码。负责异常恢复的代码应放到一个或多个 catch 块中。针对应用程序能从中安全恢复的每一种异常,都应该建立一个 catch 块。一个 try 块至少要有一个关联的 catch 块或 finally 块,单独一个 try 块没有意义,C# 也不容许。ide
开发人员有时不知道应该在一个 try 块中放入多少代码。这具体取决于状态管理。若是在一个 try 块中执行多个可能抛出同一个异常类型的操做,但不一样的操做有不一样的异常恢复措施,就应该将每一个操做都放到它本身的 try 块中,这样才能正确地恢复状态。spa
catch 块包含的是响应一个异常须要执行的代码。一个 try 块 能够关联0个或多个 catch 块。若是try 块中的代码没有形成异常的抛出,CLR 永远不会执行它的 catch块。线程将跳过全部 catch 块,直接直观性 finally 块(若是有的话)。.net
catch 关键字后的圆括号中的表达式称为捕捉类型。c# 要求捕捉类型必须是 System.Exception 或者它的派生类型。例如处理 InvalidOperationException 异常和 IOException 的 catch 块。最后一个 catch 块没有指定捕捉类型,能处理除了前面的 catch块指定的以外的其余全部异常;这至关于捕捉 System.Exception。线程
CLR 自上而下搜索匹配的 catch 块,因此应该将较具体的异常放在顶部。也就是说,首先出现的是派生程度最大的异常类型,接着是它们的基类型(若是有的话),最后是System.Exception。3d
在 try 块的代码(或者从 try 块调用的任何方法)中抛出异常,CLR 将搜索捕捉类型与抛出的异常相同(或者是它的基类)的 catch 块。若是没有任何捕捉类型与抛出的异常匹配,CLR会去调用栈更高的一层搜索与异常匹配的捕捉类型。若是都到了调用栈的顶部,仍是没有找到匹配的 catch 块就会发生未处理的异常。一旦 CRL 找到匹配的 catch 块,就会执行“内层”全部的 finally 块中的代码。所谓“内层 finally 块” 是指从抛出异常的 try 块开始,到匹配异常的 catch 块之间全部的 finally 块。注意,匹配异常的那个 catch 块所关联的 finally 块还没有执行,该 finally 块中的代码一直要等到这个 catch 块中的代码执行完毕才执行。code
static void Main(string[] args) { /* 嵌套try块 * try * { * //A * try * { * //B * } * catch * { * //C * } * finally * { * //D * } * //E * } * catch * { ... } * finally * { ... } * * 抛出异常在:内层A,E处由外层catch块捕获,并执行外层finally * 抛出异常在:内层B处,且有一合适内层catch捕获,执行内层finally,后执行E处 * 抛出异常在:内层B处,但内层catch块没有合适处理程序,执行内层finally,搜索外层catch,找合适的,执行外层finally,此时不会执行E * 抛出异常在:内层C处,退出内层catch块,执行内层finally,搜索外层catch,找到合适,执行外层finally * 抛出异常在:内层D处,退出内层finally块,搜索外层catch,找到合适,执行外层finally */ /* 使用嵌套块的缘由: * 1.修改所抛出的异常类型 * 2.在代码的不一样地方处理不一样类型的异常 */ }
以上代码转至:C#嵌套try块工做原理对象
全部内层 finally 块执行完毕后,匹配异常的那个 catch 块中的代码才开始执行。catch 块中的代码一般执行一些对异常进行处理的操做。在 catch 块的末尾,咱们有如下三个选择。blog
一、从新抛出相同的异常,向调用栈高一层的代码通知该异常的发生。
二、抛出一个不一样的异常,向调用栈高一层的代码提供更丰富的异常信息。
三、让现成从 catch 块的底部退出。(非终止线程,而是说执行正常地“贯穿” catch 块的底部,并执行匹配的 finally 块)
选择前两种技术将抛出异常,CLR 的行为和以前说的同样:回溯调用栈,查找捕捉类型与抛出的异常的类型匹配的 catch 块。
选择后一种技术,当线程从 catch 块的底部退出后,它将当即执行包含在 finally 块(这个才是与 catch 关联的 finally 块,也就是常说的 try-catch-finally 中的finally)中的代码。finally 块的全部代码执行完毕后,线程退出 finally 块,执行紧跟 finall 块以后的语句。若是不存在 finally 块,线程将从最后一个 catch 块以后的语句开始执行。
c# 容许在捕捉类型后置顶一个变量。如 ArgumentNullException e,可经过 e 查看异常的具体信息。虽然这个对象能够修改,但最好不要这么作,而应把它当成只读。