4

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

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

考虑一下这段代码......

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;
}

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

已知异常会导致性能损失,但是对于这种情况有什么想法呢?

4

6 回答 6

4

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

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

于 2009-07-10T15:14:41.960 回答
3

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

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

是的,抛出和捕获异常会消耗很多性能,最好是避免它们。

于 2009-07-10T15:09:36.587 回答
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);
}

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

于 2009-07-10T15:34:11.333 回答
1

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

如果您不需要处理异常并且它不跨越不同的架构边界,请不要处理它。如果它位于组件边界的边缘,您可能想要包装它,将原件放在内部异常中。

如果该功能是从代码中调用的,您可能想要使用一些状态表示来测试结果,例如响应(HRESULT 就是一个很好的例子。0 == SUCCESS,!= 0 == failure)或使用异常。

测试程序错误或组件故障是您将使用异常的地方,如果您在 UI 上验证来自用户的输入,您可能希望简单地使用逻辑并返回状态代码来帮助将错误传达给用户。

最后也要考虑本地化。如果您将一条英文错误消息通过系统向上传播,并将其呈现给您的法语用户,这将是无用的,并且您不想在您的 UI 上开始解析字符串以生成法语版本,那么例外是解决问题的方法只要异常的有效负载有足够的信息来生成有用的错误消息供用户采取纠正措施,就可以继续。

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

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

高温高压

于 2009-07-10T15:27:23.857 回答
1

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

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

确实,异常在 C# 中很昂贵,因此不应滥用它们。话虽如此,当你遇到错误时,50ms 左右的性能损失通常是无关紧要的,所以我倾向于使用它们来保持代码的整洁。

于 2009-07-10T15:20:49.797 回答
0

在这种情况下,我实际上会说 try/catch 是不必要的,因为您的 if 足以处理您的错误

但最下面的是我认为应该用于更复杂情况的风格

于 2009-07-10T15:10:16.227 回答