最佳实践返回值与例外与Enum的比较

时间:2014-04-02 09:43:56

标签: c# exception login enums

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

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

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);

“登录”只是一个示例案例。我想知道不同实现的优缺点,以及它们或多或少适合的情况。

4 个答案:

答案 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)

当然这取决于某些情况,但请允许我在此提供一些主观评论:

  1. 我确定应该避免这种情况。该方法的名称指出它只执行任何操作,如"登录"。根据方法名称,我们不能期望任何结果。您是否希望使用返回bool值的方法,将其命名为IsLoggedIn(userName)更好。此外,您永远不会知道是否需要扩展返回的值集。因此enum在这方面要好得多,同时考虑到价值的目标反映在enum名称而非简单bool

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

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

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

  5. 所以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
}