.NET异常处理最佳实践

1. 及早检查
发现问题越早,这个问题就越容易解决。

2. 不要相信外部数据
外部数据是不可相信的。不管这些数据是来自寄存器,数据库,硬盘,socket,你所书写的文件抑或是键盘,它们都必须被广泛的检查。所有的外部数据都应该被检查。当你需要外部数据时,你可能遇到以下的情形:
◆没有足够的安全权限.
◆信息不在那儿.
◆信息不完整.
◆信息是完整的但不可用.
不管它是注册信息,文件,SOCKET,数据库,网站服务抑或是串行端口,所有的外部数据源迟早都会出错。为安全错误做好准备才能把损失降到最小。

3. 不要抛出new Exception()
不要抛出new Exception()。Exception是一个非常大的类,如果没有side-effect,很难去捕获。引用你自己的异常类,但是使它继承自AppliationException。通过这种方法,你可以设计一个专门的异常捕获程序去捕获框架抛出的异常,同时设计另一个异常捕获程序来处理自己抛出的异常。

4. 每个线程要有单独的catch (Exception ex)语句
在你的应用程序中,普通的异常处理应该被集中解决。每个线程需要一个单独的try/catch模块,否则,你将会丢失异常导致非常难处理的问题的出现。当一个应用程序启动若干线程去做一些后台处理时,通常你需要创建一个用来存储处理结果的类。不要忘记添加用来存储可能发生的异常的区域,否则在主线程中你将无法与之通信。在”fire and forget”情况下,你可能需要在线程处理中复制主应用程序异常处理。

5. 一般的异常捕获应该被记录
你究竟使用什么工具来记录日志——log4net,EIF,Event Log,TraceListeners,text files等等都无关紧要。真正重要的是:如果你捕获一个异常,一定要在某处加以记录。但是仅记录一次.

6. 要记录Exception的全部信息而不仅是Message
在记录日志时,不要忘记应该经常性的记录Exception.ToString(),而不仅是Exception.Message。Exception.ToString()将会给你一个堆栈跟踪内部的异常和信息(messae)。通常,这个信息是及其珍贵的,如果你仅记录Exception.Message,你将会仅仅获得一些诸如“Object reference not set to an instance of an object”的信息。

7. 不要总是吞掉异常
你做的最糟糕的事情是在catch (Exception)后加了一个空的模块。永远不要这样做。

8. 清理代码应该放在finally模块中
不要把处理代码,如关闭流,恢复状态(就像鼠标指针)放在finally模块之外。要养成习惯。

9. 经常使用using
仅仅在一个对象上调用Dispose()函数是远远不够的。关键字using将会阻止资源泄漏即使在有异常出现的地方。

10. 不要用返回错误代码取代异常处理。

11. 不要把异常处理方法作为从函数中返回信息的手段
这是一个极差的设计。不仅异常的处理缓慢(就像名字暗示的一样,他们意味着只被使用在异常情况),而且代码中许多的try/catch模块会导致代码很难维护。恰当的类设计可以提供普通的返回值。如果你确实在危机中想返回数据作为一个异常,那么你的方法可能做了太多的工作需要分解。

12. 为那些不该被忽略的错误使用异常
使用现实世界的例子来说明这个问题。在开发一个API以便人们可以访问Crivo的时候,你应该做的第一件事是调用Login函数。如果Login失败,或未被调用,其他的每个函数调用将会失败。我的选择是如果Login函数调用失败就从中抛出一个异常,而不是简单的返回错误,这样调用程序就不能忽略它。

13. 当再次抛出异常时不要清空堆栈追踪

try
{
  
}
catch(Exception ex)
{
    //错误的方式
    throw ex;
}

try
{
  
}
catch(Exception ex)
{
    //正确的方式

throw;
}

14. 异常应该用[Serializable]标识
大量的情形需要异常是可序列化的。当从另一个异常类继承的时候,不要忘记增添这一属性。你将永远都不知道,你的函数什么时候将被远程组件或服务器调用。

15. 有疑惑时,不要断言,抛出异常
不要忘记Debug.Assert已经从release版本的代码中移除。在检查和确认的时候,在代码中抛出异常要比加入声明好一些。

评论: 0 | 引用: 0 | 查看次数: 4311
发表评论
登录后再发表评论!