无论是否有异常处理,用任何语言编写良好的错误处理代码都是困难的。当我考虑在一个给定的程序中需要实现什么样的异常处理时,我首先将可能捕获的每个异常分类到四个bucket中的一个,我将其标记为致命的、硬骨头般突出的、烦人的、外部的。

致命的异常不是你的错,你不能阻止它们,你也不能理智地清除它们。它们几乎总是发生,因为这一进程病入膏肓,即将摆脱痛苦。内存不足、线程中止等。捕捉这些是毫无意义的,因为你的用户代码所能做的一切都不能解决问题。就让你的“finally”块运行,并希望最好的。(或者,如果你真的很担心,快速失败和不让;在这一点上“finally”块运行,它们可能只会让事情变得更糟。但这是另一话题。)

硬骨头般突出的异常是您自己的该死的错误,您可以阻止它们,因此它们是代码中的错误。你不应该捕获它们;这样做是在你的代码中隐藏了一个错误。相反,您应该改写您的代码,这样就不可能在第一时间发生异常,因此不需要捕获异常。这个参数是空的,类型转换是坏的,索引超出范围,你试图除以零-这些都是你本来可以很容易地避免的问题,所以首先要防止混乱,而不是试图捕获它。

令人烦恼的异常是不幸的设计决策的结果。恼人的异常是在完全非异常的情况下抛出的,因此必须一直捕获和处理。典型的异常例子是Int32.Parse,如果给它一个不能被解析为整数的字符串,它就会抛出。但是这个方法99%的用例是转换用户输入的字符串,这可能是任何旧的东西,因此解析失败也不例外。更糟糕的是,如果不实现整个方法本身,调用者就无法提前确定其参数是否糟糕,在这种情况下,他们不需要首先调用它。这个不幸的设计决策非常令人恼火,当然,框架团队随后不久就实现了TryParse,这是正确的做法。你必须抓住令人恼火的异常,但这样做是令人恼火的。试着永远不要自己写一个抛出令人烦恼的例外的库。

最后,外部异常看起来有点像恼人的异常,只是它们不是不幸的设计选择的结果。相反,它们是凌乱的外部现实影响到你美丽、清晰的程序逻辑的结果。考虑这个伪C#代码,例如:

try
{
using ( File f = OpenFile(filename, ForReading) )
{
// Blah blah blah
}
}
catch (FileNotFoundException)
{
// Handle filename not found
}

标签: none

添加新评论