最佳实践返回值与例外与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);
“登录”只是一个例子。 我想知道不同实现的优点和缺点是什么,在哪些情况下它们或多或少是合适的。
当然这取决于某些情况,但让我在这里提供一些主观评论:
-
我确信应该避免这种情况。 该方法的名称指出它只执行“登录”之类的任何操作。 根据方法名称,我们不能指望任何结果。 你是否喜欢返回
bool
值的方法,将它命名为IsLoggedIn(userName)
要好得多。 此外,您永远不会知道是否需要扩展返回的值集。 因此,enum
在这里也要好得多,同时考虑到值的目标反映在enum
名称而不是简单的bool
。 -
与上述相同。 这里的例外有助于停止整个执行层次结构(当然,它可以在调用堆栈中包含多个方法),而不是仅仅返回结果并让调用者做出适当的决定。 对我来说,更灵活的解决方案。 在目前的情况下,我只使用参数validation的例外。 像“错误的用户名/密码”这样的情况并不例外。 从用例的角度来看它们是正常的。
null
参数或错误的参数格式是例外情况。 -
如果您不需要方法返回值,那就是要走的路。 不要忘记你不应该使用例外作为导航。 我的意思是
UserSuccessfullyCreatedException
左右。 -
正如我上面提到的,这对我来说是最好的方式。 唯一的一点是不要将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 }