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

前端之家收集整理的这篇文章主要介绍了从C#方法返回不同的类型前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个方法
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不仅仅是您需要的属性.在这种情况下,您需要向我们介绍更具体的例子,我们将尝试构建适合您的逻辑的抽象,如果必要的话.在这种特殊情况下 – 抽象没有意义.

猜你在找的C#相关文章