.NET中异常处理非常好的实践
代码的安全性
我的一个好朋友经常说:“一个好的程序员从不在他的项目中引用不安全的代码”。我不认为这是一个好的程序员的全部,但是的确几乎是这样。下面,我编译了一些常见的“不安全代码”,这些代码在经过异常处理后可以引用到你的项目中。
不要抛出new Exception()
不要抛出 new Exception()。Exception是一个非常大的类,如果没有side-effect,很难去捕获。引用你自己的异常类,但是使它继承自AppliationException。通过这种方法,你可以设计一个专门的异常捕获程序去捕获框架抛出的异常,同时设计另一个异常捕获程序来处理自己抛出的异常。
修订记录:在以下的评论部分中,David Levitt写信告诉我说,尽管Microsoft公司在MSDN doc中依然鼓吹使用System.ApplicationException做为基础类,但这已经不是一个好的习惯,就像Brad Adams在他的博客中所说的那样。这个方法是尽可能创造浅且宽泛的异常类层次,就像你经常处理类层次结构那样。我不马上改变文章内容的原因是在此介绍之前,我需要做更多的研究。做完这项研究后,我依然不能决定浅的类层次结构在异常处理中是否是个好办法,所以,在此处我给出了两种观点。但是,无论你做什么,不要抛出new Exception(),不要在需要时继承你自己的异常类。
不要把重要的异常信息放在message中
异常是类。当你返回异常信息时,要创建存储数据的区域。如果你没有这样做,人们为了得到所需要得信息将需要解析Message。现在,想象如果你需要局部化甚至仅仅想纠正一个错误信息中的拼写错误,会对被调用的代码造成什么影响。你也许永远都不知道你这样做会损坏多少代码。
每个线程要有单独的catch (Exception ex)语句
在你的应用程序中,普通的异常处理应该被集中解决。每个线程需要一个单独的try/catch模块,否则,你将会丢失异常导致非常难处理的问题的出现。当一个应用程序启动若干线程去做一些后台处理时,通常你需要创建一个用来存储处理结果的类。不要忘记添加用来存储可能发生的异常的区域,否则在主线程中你将无法与之通信。在"fire and forget"情况下,你可能需要在线程处理中复制主应用程序异常处理。
一般的异常捕获应该被记录
你究竟使用什么工具来记录日志——log4net, EIF, Event Log, TraceListeners,text files等等都无关紧要。真正重要的是:如果你捕获一个异常,一定要在某处加以记录。但是仅记录一次——通常代码与记录异常的catch模块一起被丢掉,然后你以一个庞大的日志结束,此日志拥有太多重复信息。
要记录Exception的全部信息而不仅是Message
在我们谈论记录日志时,不要忘记你应该经常性的记录Exception.ToString(),而不仅是Exception.Message。Exception.ToString()将会给你一个堆栈跟踪内部的异常和信息(messae)。通常,这个信息是及其珍贵的,如果你仅记录Exception.Message,你将会仅仅获得一些诸如"Object reference not set to an instance of an object".的信息。
每个线程只能有一个catch (Exception)语句
有很少的异常()遵循这一法则。如果你需要捕获一个异常,最好使用你为这段代码编写的最明确的异常类。
我经常发觉初学者认为好的代码是不抛出异常的代码。这是错误的。好的代码在需要是抛出异常,同时,仅处理那些它知道如何处理的异常。
作为这个法则的一个应用,请看以下代码。我打赌书写这段代码的人读到这儿的时候想杀我,但是这是一则摘自真实世界的例子。事实上,真实世界的代码要更复杂一些——我为了说明问题将它大大简化了。
第一个类(MyClass)在一个集合,第二个类(GenericLibrary)在另一个集合,这个集合满是普通代码。在开发机上,这段代码可以正确运行,可是在质量评价(QA)机上,这段代码经常返回“无效数据(Invalid number)”即使输入的数据是有效的。
你能说出为什麽会这样吗?
public class MyClass
...{
public static string ValidateNumber(string userInput)
...{
try
...{
int val = GenericLibrary.ConvertToInt(userInput);
return "Valid number";
}
catch (Exception)
...{
return "Invalid number";
}
}
}
![]()
public class GenericLibrary
...{
public static int ConvertToInt(string userInput)
...{
return Convert.ToInt32(userInput);
}
}
0
相关文章
