在Try,Catch,Finally中抛出异常VS返回错误

时间:2009-07-10 15:03:04

标签: exception try-catch try-catch-finally

我很确定我已经知道了答案,但我仍然很好奇在Try,Catch,Finally块中处理错误的意见是什么 - 但是当你重复自己时。< / em>的

顺便说一句 - 我不是在谈论用户输入 - 而是用它作为一个例子,因为它清晰而短暂

考虑这段代码......

try {    
    if (success) {
        return someSuccessMessage;
    }
    else {
        logError("User input not correct format");
        return someErrorMessage; // repeats itself
    }
}
catch (Exception ex) {
    logError(ex.Message);
    return someErrorMessage; // repeats itself
}

假设我们有一个函数,如果它失败了,我们想要返回一条错误消息,因为异常是无关紧要的 - 我们的函数没有成功,用户也不需要任何额外的细节。

我一直坚信,如果你能处理错误,避免异常 - 因为它不再是例外,但我想知道避免重复自己的意见......你可以做以下事情避免重复自己...

try {    
    if (success) {
        return someSuccessMessage;
    }
    else {
        throw new Exception("User input not correct format");
    }
}
catch (Exception ex) {
    logError(ex.Message);
    return someErrorMessage;
}

这不是最好的例子,但我为了简洁起见重复代码。

众所周知,例外会导致性能下降,但对于这种情况有什么想法呢?

6 个答案:

答案 0 :(得分:4)

我在这里质疑关注点的分离。除非此功能是UI的一部分,否则它不应该关注错误消息。 应该反而抛出异常。此方法的调用方(如果它是UI的一部分)可能希望生成错误消息以供显示。如果调用者是一个Web服务,那么它会想要生成一个SOAP Fault,它可能不会使用相同的消息(如果它根本使用了任何消息)。

我还强烈建议你记录ex.ToString()而不是ex.Message。

答案 1 :(得分:3)

IMO,只有在外部可纠正的情况下才应抛出异常。用户输入的格式不正确是已知的,不应抛出任何异常。

将异常视为灾难性的(火灾,地震等数据中心)。这样,您将看到处理“常规错误”和“异常”之间的区别。

是的,抛出和捕获Exception会花费很多性能,最好是避免它们。

答案 2 :(得分:2)

如果您觉得重复自己是一个问题,请将重复的代码解压缩到一个函数中。

error_code_t fail (string message) {
    logError(message);
    return someErrorMessage;
}

// ...

try {    
    if (success) {
        return someSuccessMessage;
    }
    else {
        return fail("User input not correct format");
    }
}
catch (Exception ex) {
    return fail(ex.Message);
}

老实说,我不担心在同一个函数中复制几行。

答案 3 :(得分:1)

在你的情况下,我只会返回错误消息(第一个例子),因为抛出一个异常只是为了捕获它下面的3行似乎有点奇怪。

完全不同的是,我通常会避免在可能的情况下返回错误代码 - 当我遇到错误情况时,我会通过异常并在最高级别捕获它。通过这种方式,代码不会随处可见错误处理,并且更容易看到业务逻辑。在您的情况下(如果您当然控制它),返回成功的方法可能会在发生故障时抛出异常,您根本不必提出这个问题:)

确实,C#中的例外代价很高,所以不应该滥用它们。话虽如此,当你有一个错误时,50ms左右的性能打击通常是无关紧要的,所以我倾向于使用它们来保持代码干净。

答案 4 :(得分:1)

我同意你的例子中的逻辑,但是你认为你在异常处理块和程序测试中处理的异常是什么?我怀疑你的异常处理块实际上是“万一发生了什么事”。所以它真正归结为异常处理规则。

如果您不需要处理异常,并且它没有跨越不同的架构边界,则不处理它。如果它位于组件边界的边缘,您可能希望将其包装起来,将原始文件放在内部异常中。

如果从代码中调用功能,您可能希望使用某些状态表示来测试结果,例如响应(HRESULT是其中的一个主要示例.0 == SUCCESS,!= 0 ==失败)或使用异常。

如果您要在UI上验证来自用户的输入,您可能只想使用逻辑并返回状态代码以帮助将错误传达给用户,那么您将使用异常来测试程序错误或组件故障。

最后也要考虑本地化。如果您通过系统发出英语错误消息并将其呈现给您的法语用户并且没有用,并且您不希望在UI处开始解析字符串以生成法语版本,那么异常就是通过只要异常的有效负载具有足够的信息来生成有用的错误消息,以便用户采取纠正措施。

使用组件之间紧密耦合的状态代码,并且调用组件知道在不同的状态条件下该怎么做。

BTW您可能希望使用ToString()记录堆栈跟踪以及消息,因为它将为您提供更有用的信息来解决问题。

HTH

答案 5 :(得分:0)

在这种情况下,我实际上说try / catch是不必要的,因为你的if不仅仅是在充分处理你的错误

但最底层的是我应该用于更复杂情况的风格