最佳实践返回值与例外与Enum

我试图找出具有多个结果值的方法的优点和缺点。

例如,我正在使用登录方法。 如果登录成功,它将通过,否则我需要知道它失败的原因。

1.返回true或false (信息不足)

bool Login(string user, string password); 

2.如果成功则返回true,否则抛出exception

 public class UnknownUserException : Exception { } public class WrongPasswordException : Exception { } bool Login(string user, string password); 

什么都没有。 如果不成功则抛出exception

 public class UnknownUserException : Exception { } public class WrongPasswordException : Exception { } void Login(string user, string password); 

4.返回枚举值

 enum LoginResult { Successful UnknownUser, WrongPassword } LoginResult Login(string user, string password); 

“登录”只是一个例子。 我想知道不同实现的优点和缺点是什么,在哪些情况下它们或多或少是合适的。

当然这取决于某些情况,但让我在这里提供一些主观评论:

  1. 我确信应该避免这种情况。 该方法的名称指出它只执行“登录”之类的任何操作。 根据方法名称,我们不能指望任何结果。 你是否喜欢返回bool值的方法,将它命名为IsLoggedIn(userName)要好得多。 此外,您永远不会知道是否需要扩展返回的值集。 因此, enum在这里也要好得多,同时考虑到值的目标反映在enum名称而不是简单的bool

  2. 与上述相同。 这里的例外有助于停止整个执行层次结构(当然,它可以在调用堆栈中包含多个方法),而不是仅仅返回结果并让调用者做出适当的决定。 对我来说,更灵活的解决方案。 在目前的情况下,我只使用参数validation的例外。 像“错误的用户名/密码”这样的情况并不例外。 从用例的角度来看它们是正常的。 null参数或错误的参数格式是例外情况。

  3. 如果您不需要方法返回值,那就是要走的路。 不要忘记你不应该使用例外作为导航。 我的意思是UserSuccessfullyCreatedException左右。

  4. 正如我上面提到的,这对我来说是最好的方式。 唯一的一点是不要将validationexception作为enum值。 你有例外。

所以enum结果加上validation的例外是一种方法。

如果您想在方法执行期间收集所有错误,您可能希望创建特殊的LoginOperationResult类来包装方法执行期间发生的所有信息(包括validation错误)。

 class OperationResult { public OperationStatus Status { get; set; } public IEnumerable Errors { get; set; } // or list of exceptions } class LoginOperationResult : OperationResult { // Login result specific data. } enum OperationStatus { Success, Denied, ValidationFailed, // etc. } 

你会得到更多自以为是的答案,如果我这样做,我将结合3和4.抛出LoginFailedException和enum说明原因。

 void Login(string user, string password);//Or return a bool(redundant though) class LoginFailedException : ApplicationException { public LoginFailReason Reason {get; private set;} public LoginFailedException(LoginFailReason reason) { this.Reason = reason; } } enum LoginFailReason { UnknownUser, WrongPassword } 

选择例外选项的原因:假设您选择仅返回值方法,您的api用户(可能是客户端或其他开发人员)可能会忽略API。

 instance.Login(user, password); var accountInfo = instance.GetAccountInfo();//Assuming logged in; going to explode 

谁知道他们必须这样做

 if(instance.Login(user, password) == LoginResult.Successful)) { var accountInfo = instance.GetAccountInfo(); } 

因此,IMO抛出exception表示由于某某原因我无法处理您的登录请求。 简单一点。

绝对不是例外。 失败的登录几乎不是“例外”的情况,它只是应用程序的正常逻辑过程。 如果您使用exception,那么您将始终使用exception处理程序包装登录,除了处理登录失败的情况之外没有其他原因。 这似乎是使用逻辑流exception的定义,这是不正确的。

如果您需要返回特定信息(登录function并非总是需要,但可能在您的情况下),#4似乎是合理的。 你可以更进一步,使它成为一个对象:

 public class LoginResult { // an enum for the status // a string for a more specific message // a valid user object on successful login // etc. } 

或者,根据它的逻辑,不可变的结构而不是类。 (确保结构是不可变的,可变结构只是要求麻烦。)关键是你可以在结果对象本身上应用各种逻辑和function,这似乎是你前进的方向。

我通常在我的项目中使用这种方法:

签名:

 bool TryLogin(string username, string password, out User user); 

用法:

 User user; if(userService.TryLogin(username, password, out user))) { // do stuff with user } else { // show "login failed" } 

您可以展开它以返回您的枚举:

签名:

 enum LoginResult { Successful UnknownUser, WrongPassword } LoginResult TryLogin(string username, string password, out User user); 

用法:

 User user; LoginResult loginResult; if((loginResult = userService.TryLogin(username, password, out user)) == LoginResult.Successful) { // do stuff with user } else { // do stuff with loginResult }