我有一个方法:从C#方法返回不同类型
public ??? AuthManager.Login(Credentials credentials)
下面是一组这种方法的有效输出值:
- 成功(+帐户ID)
- 失败: AccountLockedOut
- 失败:UsernameNotFound
- 失败:无效密码(+失败的尝试次数)
根据返回类型,向用户显示不同的视图(是的,AccountLockedOut的视图与InvalidPassword不同)。
我可以去:
public class LoginAttemptResult {
public bool Succeeded { get; set; }
public AccountId AccountId { get; set; } // for when success
public LoginAttemptResultEnumType Result { get;set; } // Success, Lockedout, UsernameNotFound, InvalidPassword
public int FailedAttemptCount { get; set; } // only used for InvalidPassword
}
我不喜欢这一点,寻找一个更好的解决方案。首先,这导致部分初始化对象,两个违反界面分离原则,三个违反SRP。
更新:抛出异常也不是一个优雅的解决方案,因为我看到它InvalidPassword
并不是一个例外。数据库连接失败是一个例外。空参数是一个例外。 InvalidPassword
是有效的预期响应。
我认为更好的解决方案是创建一个类层次:
abstract class LoginAttemptResult
sealed class LoginSuccess : LoginAttemptResult { AccountId }
abstract class LoginFailure : LoginAttemptResult
sealed class InvalidPasswordLoginFailure : LoginFailure { FailedAttemptCount }
sealed class AccountLockedoutLoginFailure : LoginFailure
Login
方法的调用,然后将不得不做这样的事情:
if (result is LoginSuccess) {
..."welcome back mr. account id #" + (result as LoginSuccess).AccountId
}
else if (result is InvalidPasswordLoginFailure) {
..."you failed " + (result as InvalidPasswordLoginFailure).FailedAttemptCount + " times"
}
我看不出有什么错(概念上)采用这种方法(除了它自带的许多类)。
这种方法还有什么问题吗?
请注意,这种方法本质上是F#的discriminated union (DU)。
有没有更好的方法来建模?我已经有几个解决方案可行 - 现在我想要一个优雅的解决方案。
会投掷你的项目失败的例外情况? – Dirk 2013-05-03 15:28:47
Dirks的建议很有意义 - 当一切正常时返回登录信息 - 当事情出错并引发任何需要的信息时抛出异常。代码看起来并不关键,但问题是......“登录失败是一种特殊情况?”。 ASP.NET成员资格有什么作用? AD如何? – Charleh 2013-05-03 15:30:51
想到这一点,但我不认为失败的登录是一个例外情况。如果我无法连接到数据库,或者凭据为空,则会抛出异常 - 这些异常。我可以将方法重命名为'TryLogin',以清楚地表明它尝试登录,这种失败尝试是预期的响应之一。 – 2013-05-03 15:31:34