当一个类型的行动成员不能正在完整行动任务时,就应该抛出异常通知调用者。
*行动成员指类型本身或者类型实例可以执行的操作,如C#中StringBuilder中定义的Append,Insert等
private void DoSomething() { try { //将可能发生异常的代码放在这里 } catch (InvalidOperationException) { //捕捉到InvalidOperationException异常,对应的处理代码放在这里 } catch (IOException) { //捕捉到IOException异常,对应的处理代码放在这里 } catch (Exception) { //捕捉到除了上述之外的其它异常,对应的处理代码放在这里 //这里是将异常抛出 throw; } finally { //这里的代码总是被执行 } //如果try块没有抛出异常或者某个catch捕捉到异常却没有抛出就执行以下的代码,否则以下代码不执行 }
try块中包含的是可能会发生异常的代码,异常恢复代码应放在一个或多个catch块中。针对应用程序安全的恢复某一种异常都需要有一个对应的catch块。一个try块至少要关联一个catch块或finally块,单独一个try块C#是不允许的,而且这样也没有意义。
*如果一个try块中包含执行多个可能抛出同一个异常类型的操作,但不同的操作对应的恢复措施不同,我们就应该将这些操作拆分到它自己的try块中,以保证正确的恢复状态
catch块包含的是响应一个异常需要执行的代码。一个try块可以关联0个或多个catch块。如果try块中的代码没有异常发生,CLR永远不会执行catch块中的代码。线程将跳过所有catch块,直至finally块(里面有代码的话)中的代码。catch关键字后面圆括号中的表达式称为捕捉类型,即要捕捉的异常类型。
*使用Visual Studio调试catch块时,可以在监视窗口中添加特殊的变量名称$exception来检查当前抛出异常的对象
CLR是自上而下检索一个匹配的catch块,所以编程的时候应注意将派生程度最大的异常类型放在顶部,接着是它们的基类,最后才是System.Exception,如果顺序没有放对,例如将最具体的异常类型放在了最底部的catch块中,C#编译器将会发生错误,因为这个catch块无法被执行到。
一旦try块中的代码发生异常,而没有与之匹配的catch块的话,CLR会去调用栈的更高一层搜索与之匹配的异常类型,如果到了栈的顶部还是没有找到,就会发生一个未处理的异常。
前两种技术CLR将回溯调用栈,查找捕捉类型与抛出异常的类型匹配的catch块并抛出一个异常。
如果选择让线程从catch块的底部退出,将立即执行包含在finally块中的代码,完毕后执行紧跟在finally块之后的语句。如果不存在finally块,线程将从最后一个catch块之后的语句开始执行。
finally块中的代码是保证一定会执行的代码且一定要在所有catch块的后面,通常包含的是对try块中的行动所要求的资源清理操作。一个try块最多只能关联一个finally块。
private void ReadFile(string path) { FileStream fs = null; try { fs = new FileStream(path, FileMode.Open); //处理文件数据... } catch (IOException) { //IOException异常恢复代码 } finally { //确保文件关闭 if (fs != null) fs.Close(); } }
上述代码,无论try块代码有没有发生异常,文件都一定会被关闭。如果将关闭文件的代码放在finally块语句之后是不正确的,因为如果抛出异常但没有捕捉到,finally块之后的语句将永远不会被执行,直到下一次垃圾回收才会关闭文件。
*一般情况下catch块和finally块中的代码应只有一两行
private string SomeMothods() { var result = ""; var a = 1; var b = 0; try { a /= b; } catch (DivideByZeroException) { result = "被除数不能为0"; } return result; }
异常抛出时,CLR会在调用栈中向上查找与抛出异常对象的类型匹配的catch块。如果没有找到,就会发生一个未处理的异常。当CLR检测到进程中的任意一个线程有未处理的异常,都会终止进程。发生未处理异常表明程序遇到了未预料的情况。同时,发生未处理的异常时windows会向事件日志写入一条记录,可以打开事件查看器查看
异常设置
可通过调试菜单打开异常设置窗口如图
展开Common Languages Runtime Exceptions可以查看Visual Studio能够识别的异常类型
如果勾选了异常类型的复选框,调试器就会在抛出该异常的时候中断,此时CLR不会查找任何与之匹配的catch块。
如果异常类的复选框没有勾选,调试器只有在该异常类型未得到处理时才会中断。
通过添加操作还可以添加自定义的异常类型