bindsang

工作五年,长期从事于asp.net方面的编程,业余爱好VC编程,温和、谦虚、自律、自信、善于与人交往沟通
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C#异常处理的方式

Posted on 2012-06-26 16:22    阅读(2684)  评论(2编辑  收藏  举报

 

C#异常处理的方式

 

c#中所有可以被抛出的异常都是直接或间接继承自System.Exception

 

支持的捕获异常的语句块如下:

try … catch

try … catch … finally

try… finally

 

c#代码块中生成异常堆栈信息的时机不是在throw语句执行的地方,而是在第一次捕获的地方

 

以上三种方式中 try ... finally一定不会影响堆栈信息

可能会影响的地方主要集中在catch块中

 

catch子句声明方式又有以下几种

 

catch{}

catch(Exception){}

catch(Exception ex){}

 

这三种写法从捕获异常的能力上来说基本上是等效

第三种方式只是让编写代码的人可以使用异常参数,如果不使用异常参数的话可以用前面两种,第二种只是更加明确的指出了捕获的是Exception或者是从Exception继承的异常

 

catch块内可以再次抛出异常,抛出时可以支持下面几种方式

 

throw;

throw ex; // ex来自于catch(Exception ex)

throw new SomeException();

 

后面两种情况是一样的, stack trace认为你catch到的异常已经被处理了,只不过处理过程中又抛出新的异常,这时候stack trace就把throw 后的那个异常实例当作错误根源了。之前的堆栈信息全部会清除掉

第一种方式网上和MSDN上都说可以保留堆栈信息。经测试发现不全是如此:

Debug版本下,生成的代码在执行没有任何优化,直接使用throw;这种方式的确是能保留堆栈信息。这个时候的堆栈信息就好像是在try块内部异常产生的地方就记录好了一样。

Release下,输出的信息中只包含了从捕获位置开始向上的堆栈信息。即从异常源发生位置到第一次catch块捕获发生之间的堆栈信息都不存在了

 

总结如下:

以前的异常信息中有出错的点很容易就找到了,那是因为正巧异常源与第一次捕获的地方很接近

否则的话越是在调用的最上层捕获到异常,越不容易找到异常源在什么位置(这里都是在Release条件下)

Release版本下,异常越早捕获,越能精确定位出错位置,越晚捕获,从堆栈中获得的获得的有效信息也越少,即使是用了throw;这样的方式也一样

严格禁止 下面这种写法:

try{

         // do

}

catch(Exception ex)

{

throw ex;

}

如有必要需改用 throw; 或者 throw new SomeException(msg, ex); 这样的形式

 

如果是捕获了异常不想再次抛出(一般用在捕获到的异常在预期范围内,已经有相应的处理方式了),最好是能记录日志,表示发生过异常

 

 

附上一个测试:

Release 使用throw;

Release 使用throw ex;

 

 

Release下更极端的例子去掉了除最外层外所有的try…catch

 

 

 

Debug 使用throw;

 

 

Debug 使用throw ex;