我在这两种错误处理模型之间徘徊:
为对象创建布尔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
在对象中抛出异常并使用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
对我而言,除了您拥有Error
和ErrorMessage
属性的属性代码之外,它似乎都是相同数量的代码。但是,您也可以在不检查异常的情况下判断何时发生错误。我应该选择哪种模式?
答案 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参数,以便调用者明确地知道需要处理返回的错误。