我目前正在进行代码审查,以下代码让我跳了起来.我看到这个代码存在多个问题.你是否同意我的观点?如果是这样,我如何向我的同事解释这是错误的(顽固型......)?
捕获一般异常(Exception ex)
使用"if(ex is something)"而不是另一个catch块
我们吃SoapException,HttpException和WebException.但是如果Web服务失败了,那就没那么多了.
码:
try { // Call to a WebService } catch (Exception ex) { if (ex is SoapException || ex is HttpException || ex is WebException) { // Log Error and eat it. } else { throw; } }
Michael Hare.. 15
口头禅是:
如果能够正确处理异常,您应该只捕获异常
从而:
你不应该抓住一般例外.
在你的情况下,是的,你应该抓住那些例外并做一些有用的事情(可能不仅仅是吃它们 - 你可以throw
在记录它们之后).
你的编码器正在使用throw
(不是throw ex
)哪个好.
这是您可以捕获多个特定异常的方法:
try { // Call to a WebService } catch (SoapException ex) { // Log Error and eat it } catch (HttpException ex) { // Log Error and eat it } catch (WebException ex) { // Log Error and eat it }
这几乎与您的代码相同.您的dev可能就是这样做的,以避免重复"日志错误并吃掉它"块.
口头禅是:
如果能够正确处理异常,您应该只捕获异常
从而:
你不应该抓住一般例外.
在你的情况下,是的,你应该抓住那些例外并做一些有用的事情(可能不仅仅是吃它们 - 你可以throw
在记录它们之后).
你的编码器正在使用throw
(不是throw ex
)哪个好.
这是您可以捕获多个特定异常的方法:
try { // Call to a WebService } catch (SoapException ex) { // Log Error and eat it } catch (HttpException ex) { // Log Error and eat it } catch (WebException ex) { // Log Error and eat it }
这几乎与您的代码相同.您的dev可能就是这样做的,以避免重复"日志错误并吃掉它"块.
我目前正在进行代码审查,以下代码让我跳了起来.我看到这个代码存在多个问题.你是否同意我的观点?
不完全,见下文.
捕获一般异常(Exception ex)
一般来说,只要你重新抛出它(带有throw;),当你得出你无法处理它的结论时,捕获一般异常实际上是可以的.代码就是这样,所以这里没有直接的问题.
使用"if(ex is something)"而不是另一个catch块
catch块的净效果是实际上只处理SoapException,HttpException等,并且所有其他异常都在调用堆栈中传播.我想功能方面,这就是代码应该做的事情,所以这里也没有问题.
然而,从美学和可读性POV我更喜欢多个catch块到"if(ex是SoapException || ..)".一旦将公共处理代码重构为方法,多个catch块只会稍微打字,并且对于大多数开发人员来说更容易阅读.而且,最后一击很容易被忽视.
我们吃SoapException,HttpException和WebException.但是如果Web服务失败了,那就没那么多了.
这里可能潜伏着代码的最大问题,但是在不了解应用程序性质的情况下很难提供建议.如果Web服务调用正在执行您以后依赖的操作,那么仅记录和使用异常可能是错误的.通常,您将异常传播给调用者(通常在将其包装到例如XyzWebServiceDownException之后),甚至可能在重试webservice调用几次之后(在存在虚假网络问题时更加健壮).
捕获和重新抛出相同异常的问题在于,虽然.NET尽最大努力保持堆栈跟踪完好无损,但它总是会被修改,这可能会导致跟踪故障实际来自更加困难的地方(例如异常)行号可能看起来是重新抛出语句的行而不是最初引发异常的行.有关捕获/重新抛出,过滤和未捕获之间差异的更多信息.
当存在像这样的重复逻辑时,你真正需要的是一个异常过滤器,所以你只能捕获你感兴趣的异常类型.VB.NET有这个功能,但不幸的是C#没有.假设的语法可能如下所示:
try { // Call to a WebService } catch (Exception ex) if (ex is SoapException || ex is HttpException || /* etc. */) { // Log Error and eat it }
虽然你不能这样做,但我倾向于使用lambda表达式作为公共代码(你可以delegate
在C#2.0中使用),例如
ActionlogAndEat = ex => { // Log Error and eat it }; try { // Call to a WebService } catch (SoapException ex) { logAndEat(ex); } catch (HttpException ex) { logAndEat(ex); } catch (WebException ex) { logAndEat(ex); }