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

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

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


当前回答

If it's code running inside a loop that will likely cause an exception over and over again, then throwing exceptions is not a good thing, because they are pretty slow for large N. But there is nothing wrong with throwing custom exceptions if the performance is not an issue. Just make sure that you have a base exception that they all inherite, called BaseException or something like that. BaseException inherits System.Exception, but all of your exceptions inherit BaseException. You can even have a tree of Exception types to group similar types, but this may or may not be overkill.

因此,简短的回答是,如果它不会导致显著的性能损失(除非抛出大量异常,否则不应该如此),那么就继续执行。

其他回答

异常类就像“正常”类。当一个新类“是”一个不同类型的对象,具有不同的字段和不同的操作时,您可以创建一个新类。

As a rule of thumb, you should try balance between the number of exceptions and the granularity of the exceptions. If your method throws more than 4-5 different exceptions, you can probably merge some of them into more "general" exceptions, (e.g. in your case "AuthenticationFailedException"), and using the exception message to detail what went wrong. Unless your code handles each of them differently, you needn't creates many exception classes. And if it does, may you should just return an enum with the error that occured. It's a bit cleaner this way.

You may use a little bit generic exceptions for that conditions. For e.g. ArgumentException is meant to be used when anything goes wrong with the parameters to a method (with the exception of ArgumentNullException). Generally you would not need exceptions like LessThanZeroException, NotPrimeNumberException etc. Think of the user of your method. The number of the conditions that she will want to handle specifically is equal to the number of the type of the exceptions that your method needs to throw. This way, you can determine how detailed exceptions you will have.

顺便说一下,总是尝试为库的用户提供一些避免异常的方法。TryParse就是一个很好的例子,它的存在使你不必使用int。解析并捕获异常。在您的情况下,您可能希望提供一些方法来检查用户名是否有效或密码是否正确,这样您的用户(或您)就不必进行大量异常处理。这将有望产生更易于阅读的代码和更好的性能。

一般来说,你想要为应用程序中可能发生的任何异常抛出一个"异常"

在您的示例中,这两个异常看起来都是通过密码/用户名验证调用的。在这种情况下,有人会输入错误的用户名/密码并不是什么例外。

它们是UML主要流程的“例外”,但在处理过程中是更多的“分支”。

如果您试图访问您的passwd文件或数据库,但无法访问,这将是一个异常情况,并需要抛出异常。

异常与返回错误代码参数应该是关于流控制的,而不是哲学(错误有多“异常”):

void f1() throws ExceptionType1, ExceptionType2 {}

void catchFunction() {
  try{
    while(someCondition){
      try{
        f1(); 
      }catch(ExceptionType2 e2){
        //do something, don't break the loop
      }
    }
  }catch(ExceptionType1 e1){
    //break the loop, do something else
  }

}

因为它们是正常发生的事情。异常不是控制流机制。用户经常会输入错误的密码,这不是特例。异常应该是一个真正罕见的事情,UserHasDiedAtKeyboard类型的情况。