加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

从C#方法返回不同的类型

发布时间:2020-12-15 03:56:22 所属栏目:百科 来源:网络整理
导读:我有一个方法: public ??? AuthManager.Login(Credentials credentials) 以下是此方法的一组有效输出值: 成功(accountId) 失败:AccountLockedOut Failure:UsernameNotFound 失败:InvalidPassword(尝试次数失败) 根据返回类型,不同的视图会显示给用户(是
我有一个方法:
public ??? AuthManager.Login(Credentials credentials)

以下是此方法的一组有效输出值:

>成功(accountId)
>失败:AccountLockedOut
> Failure:UsernameNotFound
>失败:InvalidPassword(尝试次数失败)

根据返回类型,不同的视图会显示给用户(是的,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不是一个例外. DB连接失败是一个例外.空参数是一个例外. 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).

有更好的方法来建模吗?我已经有几个解决方案可行 – 现在我想要一个优雅的解决方案.

解决方法

如果结果类显着不同,您需要一个单独的类,我认为您的解决方案是可行的.但我不知道那个.为每个结果尝试此类:
/// <summary>
/// Immutable,created by the server
/// </summary>
class LoginResult
{
    /// <summary>
    /// Null in the case of failure
    /// </summary>
    public int? Id { get; private set; }

    /// <summary>
    /// Null in the case of success
    /// </summary>
    public string FailReason { get; private set; }

    /// <summary>
    /// Always >= 1
    /// </summary>
    public int AttemptNumber { get; private set; }

    public LoginResult(int id,int attemptNumber)
    {
        Id = id;
        AttemptNumber = attemptNumber;
    }

    public LoginResult(string reason,int attemptNumber)
    {
        FailReason = reason;
        AttemptNumber = attemptNumber;
    }
}

我可以想象,您的身份验证逻辑可能非常复杂,Id,FailReason和AttemptNumber不仅仅是您需要的属性.在这种情况下,您需要向我们介绍更具体的例子,我们将尝试构建适合您的逻辑的抽象,如果必要的话.在这种特殊情况下 – 抽象没有意义.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读