我试图找出具有多个结果值的方法的优点和缺点。
例如我正在使用登录方法。如果登录成功,它将通过,否则我需要知道它失败的原因。
1。返回true或false (信息不足)
bool Login(string user, string password);
2。返回true,如果成功,否则抛出异常
public class UnknownUserException : Exception { }
public class WrongPasswordException : Exception { }
bool Login(string user, string password);
第3。没有回报。如果不成功则抛出异常
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);
“登录”只是一个示例案例。我想知道不同实现的优缺点,以及它们或多或少适合的情况。
答案 0 :(得分:3)
你会得到更多自以为是的答案,如果我这样做,我将结合3& 4.向LoginFailedException
投掷枚举说明原因。
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抛出异常,因为出于某种原因,我无法处理您的登录请求。简单。
答案 1 :(得分:3)
当然这取决于某些情况,但请允许我在此提供一些主观评论:
我确定应该避免这种情况。该方法的名称指出它只执行任何操作,如"登录"。根据方法名称,我们不能期望任何结果。您是否希望使用返回bool
值的方法,将其命名为IsLoggedIn(userName)
更好。此外,您永远不会知道是否需要扩展返回的值集。因此enum
在这方面要好得多,同时考虑到价值的目标反映在enum
名称而非简单bool
。
与上述相同。这里的例外有助于停止整个执行层次结构(当然,它可以在调用堆栈中包含多个方法),而不是仅仅返回结果并让调用者做出适当的决定。对我来说更灵活的解决方案。在目前的情况下,我只使用参数验证的例外。像"错误的用户名/密码"不例外。从用例的角度来看,它们是正常的。 null
参数或错误的参数格式是例外情况。
如果您不需要该方法来返回值,那就是要走的路。不要忘记你不应该使用异常作为导航。我的意思是UserSuccessfullyCreatedException
左右。
正如我上面提到的,这对我来说是最好的方式。唯一的一点是不要将验证异常作为enum
值。你有例外。
所以enum
结果加上验证的例外是一种方法。
如果您想在方法执行期间收集所有错误,您可能希望创建特殊的LoginOperationResult
类来包装方法执行期间发生的所有信息(包括验证错误)
class OperationResult
{
public OperationStatus Status { get; set; }
public IEnumerable<ValidationError> Errors { get; set; }
// or list of exceptions
}
class LoginOperationResult : OperationResult
{
// Login result specific data.
}
enum OperationStatus
{
Success,
Denied,
ValidationFailed,
// etc.
}
答案 2 :(得分:2)
绝对不是例外。失败的登录几乎不是“例外”的情况,它只是应用程序的正常逻辑过程。如果您使用异常,则除了处理登录失败的情况之外,您将始终必须使用异常处理程序包装登录。这似乎是使用逻辑流异常的定义,这是不正确的。
如果您需要返回特定信息(登录功能不是总是,但可能在您的情况下),#4似乎是合理的。你可以更进一步,使它成为一个对象:
public class LoginResult
{
// an enum for the status
// a string for a more specific message
// a valid user object on successful login
// etc.
}
或者,取决于它的逻辑,不可变的结构而不是类。 (确保结构是不可变的,可变结构只是要求麻烦。)关键是你可以在结果对象本身上应用各种逻辑和功能,这似乎是你前进的方向。
答案 3 :(得分:1)
我通常在我的项目中使用这种方法:
签名:
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
}