哪种错误处理模型更强大?

时间:2009-09-13 18:39:48

标签: vb.net error-handling

我在这两种错误处理模型之间徘徊:

  1. 为对象创建布尔Error和字符串ErrorMessage属性。在对象的方法内部捕获所有异常,并使用来自调用者的条件逻辑传递消息,即:

    Dim o As New MyObject
    o.SomeMethod()
    If Not o.Error Then
        'Do stuff'
    Else
        Dim msg As String = o.ErrorMessage
        'do something with message'
    End If
    
  2. 在对象中抛出异常并使用Try Catch逻辑在外部处理它们:

    Dim o As New MyObject
    Try
       o.SomeMethod()      
       'Do stuff'
    Catch ex As Exception
        Dim msg As String = ex.ErrorMessage
        'do something with message'
    End Try
    
  3. 对我而言,除了您拥有ErrorErrorMessage属性的属性代码之外,它似乎都是相同数量的代码。但是,您也可以在不检查异常的情况下判断何时发生错误。我应该选择哪种模式?

6 个答案:

答案 0 :(得分:7)

我决定抛出异常而不是使用错误/返回代码。我最近才非常努力。

抛出异常的第一个原因是您可能忘记检查错误代码。如果您不检查它,那么您将在错误存在时继续工作。但有例外,如果您忘记处理它们,则异常将升至顶部并停止所有处理。发生这种情况比发生未知错误后继续发生更好。

有关详细信息,请查看Addison-Wesley的 Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, Second Edition 中的例外情况。

Joel Spolsky实际上更喜欢错误/返回代码而不是异常,但很多人不同意他的看法。可以找到Joel的帖子,支持返回代码here。查看this blog post以及所有评论,并就此主题进行一些很好的讨论。

答案 1 :(得分:3)

首选#2。有关详细信息,请参阅Dennis提到的Microsoft excerpt on Exception Throwing开发中的Framework Design Guidelines。请特别注意有关例外和性能的部分。

简短版本:

  

不要返回错误代码。

     

通过抛出异常来报告执行失败。

     

不要将异常用于正常的控制流程。

我强烈建议您阅读本书进行全面讨论,并附上一些微软名人的评论。

答案 2 :(得分:3)

当发生异常时,应使用例外。

e.g。当你期望它时,你会传递一个null(无)对象。

Bob叔叔在他的书Clean code中建议使用错误代码例外。

他说

  

这些[错误代码]方法的问题在于它们使调用者混乱。呼叫者必须在呼叫后立即检查错误。不幸的是,它很容易忘记。因此,最好在遇到错误时抛出异常。调用代码更清晰。它的逻辑不会被错误处理所掩盖。

答案 3 :(得分:2)

我对第一个问题的最大问题是它被动,容易被忽视而且不是很标准化。程序员如何知道检查该属性?或者哪些属性/方法可以设置错误?或者哪个属性/方法访问导致错误被设置?

例如。在你的第一个示例代码中,如果o.Error为True,则不清楚对象的初始化或对SomeMethod的调用是否导致设置了标志。

异常模型是告诉用户发生错误的一种不可靠的方式。没有明确的代码来处理这种情况就无法避免。

答案 4 :(得分:2)

它们都是可接受的错误处理形式,但.NET语言的首选是使用异常。

使用返回码(数字或布尔值)有一些问题,最大的两个是:

  • 程序员容易忽视/忽略。
  • 不能在所有情况下使用。如果您的构造函数失败会发生什么?您无法从构造函数中显式返回值。

仅出于这些原因,您应该使用例外。例外提供了一种清晰,标准化的方式来表明和任何失败,无论它出现在何处。

您最终会得到更少的代码,因为您应该只能在安全且适当地处理该异常的时间和地点捕获异常。

答案 5 :(得分:1)

我建议同时使用。

<强>为什么吗

“使用合适的工具”

返回码的“问题”是人们经常忘记处理它们。但是,异常并不能解决这个问题!人们仍然不处理异常(他们没有意识到需要处理某个异常,他们假设堆栈中的某个人会处理它,或者他们使用catch()并压缩所有错误)。

虽然未处理的返回代码可能意味着代码处于不稳定状态,但未处理的异常通常保证程序将崩溃。这样更好吗?

虽然在编写代码时很容易识别返回代码,但通常不可能(或者只是繁琐耗时)确定您调用的方法可能抛出的异常。这通常会导致很多非常糟糕的异常处理。

异常应该用于“错误”。这就困难了。如果在尝试打开文件时找不到文件,那是“错误”还是“预期情况”?只有来电者知道。在任何地方使用例外基本上都会将每条状态信息提升为错误。

最终,错误处理是程序员必须要做的事情。返回代码和异常都存在此问题。

因此,我使用返回码传递状态信息(包括“警告”)和“严重错误”的例外。 (是的,有时候很难判断某个类别属于哪个类别)

来自.net的案例

Int32.Parse抛出异常(即使它的异常都不是错误 - 由调用者验证结果并自行决定结果是否有效)。并且只需要在try / catch中包含对它的每次调用都是一种痛苦(以及性能损失)。如果您忘记使用try / catch,则简单的空白文本输入字段可能会导致程序崩溃。

因此,Int32.TryParse()诞生了。这会做同样的事情,但返回错误代码而不是异常,这样您就可以简单地忽略错误(对于任何非法输入接受默认值0)。在许多现实生活中,这比Int32.Parse()更清晰,更快速,更简单,更安全。

“TryParse”使用命名约定使调用者清楚可能发生错误,应该正确处理。另一种方法(强制程序员更好地处理错误)是将返回代码转换为out或ref参数,以便调用者明确地知道需要处理返回的错误。