我为我的应用程序不期望的每个条件创建了异常。UserNameNotValidException, PasswordNotCorrectException等。

然而,我被告知我不应该为这些条件创造例外。在我的UML中,那些是主要流程的异常,那么为什么它不应该是异常呢?

是否有创建异常的指导或最佳实践?


当前回答

我个人的指导方针是:当发现当前代码块的基本假设为假时抛出异常。

例1:假设我有一个函数,它应该检查任意类,如果该类继承自List<>,则返回true。这个函数问一个问题:“这个对象是List的后代吗?”这个函数永远不会抛出异常,因为它的操作中没有灰色地带——每个单独的类要么继承了List<>,要么继承了List<>,所以答案总是“是”或“否”。

Example 2: say I have another function which examines a List<> and returns true if its length is more than 50, and false if the length is less. This function asks the question, "Does this list have more than 50 items?" But this question makes an assumption - it assumes that the object it is given is a list. If I hand it a NULL, then that assumption is false. In that case, if the function returns either true or false, then it is breaking its own rules. The function cannot return anything and claim that it answered the question correctly. So it doesn't return - it throws an exception.

这与“负载问题”逻辑谬误相当。每个函数都问一个问题。如果给出的输入使该问题成为谬误,则抛出异常。对于返回void的函数,这条线很难画出来,但底线是:如果函数对其输入的假设违反了,它应该抛出异常,而不是正常返回。

这个等式的另一方面是:如果你发现你的函数经常抛出异常,那么你可能需要改进它们的假设。

其他回答

在决定异常是否合适时,需要考虑一些有用的事情:

what level of code you want to have run after the exception candidate occurs - that is, how many layers of the call stack should unwind. You generally want to handle an exception as close as possible to where it occurs. For username/password validation, you would normally handle failures in the same block of code, rather than letting an exception bubble up. So an exception is probably not appropriate. (OTOH, after three failed login attempts, control flow may shift elsewhere, and an exception may be appropriate here.) Is this event something you would want to see in an error log? Not every exception is written to an error log, but it's useful to ask whether this entry in an error log would be useful - i.e., you would try to do something about it, or would be the garbage you ignore.

抛出异常会导致堆栈unwind,这对性能有一定影响(承认,现代托管环境在这方面有所改进)。仍然在嵌套的情况下反复抛出和捕获异常是一个坏主意。

可能比这更重要的是,例外是针对特殊情况的。它们不应该用于普通的控制流,因为这会损害代码的可读性。

主要有两类异常:

1)系统异常(如数据库连接丢失)或 2)用户异常。(例如用户输入验证,“密码不正确”)

我发现创建自己的用户异常类很有帮助,当我想抛出一个用户错误时,我想要以不同的方式处理(即资源错误显示给用户),然后我在我的主错误处理程序中所需要做的就是检查对象类型:

            If TypeName(ex) = "UserException" Then
               Display(ex.message)
            Else
               DisplayError("An unexpected error has occured, contact your help  desk")                   
               LogError(ex)
            End If

避免抛出异常的主要原因是抛出异常涉及大量开销。

下面这篇文章指出的一件事是,例外是针对异常条件和错误的。

错误的用户名不一定是程序错误,而是用户错误……

下面是关于。net中的异常的一个不错的起点: http://msdn.microsoft.com/en-us/library/ms229030 (VS.80) . aspx

抛出异常的经验法则非常简单。当你的代码进入UNRECOVERABLE INVALID状态时,你可以这样做。如果数据被泄露,或者您无法回溯到目前为止发生的处理,那么您必须终止它。你还能做什么呢?您的处理逻辑最终将在其他地方失败。如果你能以某种方式恢复,那么就这样做,不要抛出异常。

在你的特定情况下,如果你被迫做一些愚蠢的事情,比如接受提款,然后才检查用户/密码,你应该通过抛出一个异常来终止这个过程,通知发生了一些不好的事情,并防止进一步的损害。