基本结构
try { } catch(other exception) { ///用于捕捉各种具体的异常,具体的异常会在这里对它进行马上处理 } catch(exception) { ///这里会捕捉到除了上面的所有异常,但一般需要重新抛出异常 } finally { ///无论上面代码怎么样执行,最后都要执行该区域代码,用于做一些清理等动作 }
规则
1、try语句至少要有一个对应的catch或finally,不允许单独一个try语句
2、如果到了调用栈顶部,仍然没有找到匹配的catch语句,就会发生未处理异常
3、找到匹配的catch块后,会先执行内层的所有finally语句,就是从抛出异常的try语句开始,到匹配异常的catch语句之间的所有finally语句。但是匹配catch语句的那个finally语句要等该catch语句执行完毕之后才能执行
4、catch语句的处理方式一般有三种
1)、向上面抛出一个相同的异常
2)、向上面抛出一个不同的异常,通常可提供更丰富的异常信息
3)、处理异常,不向上抛异常。
5、catch和finally块中的代码应该非常短,避免又出现异常。即使在catch或finally语句中抛出了异常,clr会向上抛出这个新的异常,只不过原来try语句中的异常信息就会被这个新的异常覆盖掉,一般会成为一个未处理的异常。
6、在catch语句向上抛异常,使用“throw”和“throw e”语句是有区别的,前者不会重置异常的起点,后者则会,将起点重置为throw语句这里。
7、执行catch或finally块时,clr不允许线程终止
8、在设计类库的异常时,不要自己处理异常,要抛出异常,让调用者自己去处理,如果在类库内部处理,对调用者来说就不透明,也不友好
9、禁止只捕获Exception异常而不重新抛出它,否则应用程序不知道已经出错,还会继续运行
Exception类中的常用信息字段
Message:指出抛出异常原因的文字性说明
Source:指出生成异常的程序集名称
StackTrace:包含抛出异常之前调用过的所有方法
InnerException:如果当前异常是在处理一个异常时抛出的,该属性就指向上一个异常
AppDomain FirstChanceException
这个事件是在发生异常后clr在搜索所有catch块之前发生的。因此,可利用这个事件监视AppDomain抛出的异常,添加日志记录等操作,使用原则如下
1、该事件不能处理异常,只是用于接收异常的通知
try...finally语句在某些常用的常用的操作中有省略的写法,编译器最后都会把这些省略写法还原为try...finally写法
1、lock语句,锁在finally中释放
2、using语句,在finally语句中调用Dispose方法
3、foreach语句,在finally语句中调用IEnumerator的Dispose方法
4、析构方法,在finally语句中调用Finalize方法
未处理的异常
类库开发人员压根用不着去想未处理的异常,只有应用程序的开发人员才需要关心未处理的异常,MS建议应用程序开发人员接收CLR的默认策略。也就是发生未处理异常时,windows会向事件日志写一条记录,可以再控制面板-》事件查看器-》windows日志-》应用程序中查看。
Application.ThreadException AppDomain.CurrentDomain.UnhandledException
1、前者用于捕捉ui线程的未处理异常,此时后者是捕捉不到的,并且前者也是UI线程所特有的异常,后者用于捕获非UI线程中的为处理异常
2、在前者异常中,如果没有实现该事件,则会弹出下列的界面,此时无论是点“继续”还是“退出”按钮,都不会向事件日志中写记录,点击继续按钮,程序继续,点击“退出”立即退出进程,不会也不会执行Application的ThreadExit和ApplicationExit事件
3、如果实现前者事件,并不抛出新的异常,则异常到此为止,windows也不会向事件日志中写记录
4、如果实现前者事件,并在实现程序中在再次抛出该异常,则会弹出下面的提示框,并且windows会向事件日志中写记录,同时也会执行Application的ThreadExit和ApplicationExit事件
Application.ApplicationExit Application.ThreadExit异常处理的关系
1、如果是正常结束程序,或者用任务管理器强制关闭程序都会触发这两个事件
2、但是如果没有实现未处理异常的事件,并弹出的未处理提示框中点退出按钮,则不会执行这两个事件,很奇怪