忽略标准 C# 结果类中 Fail 方法中的类型

问题描述 投票:0回答:1

我已经使用结果类很多年了,当我接触 C# 时,我第一次遇到的是 John Ottosson 结果类。这是我用作自己目的基础的结果类的版本,多年来一直为我服务。但它并非没有缺陷,我花了很多时间试图找出更优雅的方法来让它发挥作用。

这是 C# 结果类的典型实现。

public class Error
{
    public string Message { get; set; }
   //left out other properties for brevity
}

public class Result
{
    //If there are no errors, then it is a successful call
    public bool IsSuccessful => Errors?.Any() ?? true;
    public IReadOnlyList<Error>? Errors { get; set; }
    
    public static Result<T> Success<T>(T data)
    {
        return new Result<T>
        {
            Data = data,
            Errors = null
        };
    }
    
    public static Result<T> Fail<T>(Error error)
    {
        return new Result<T>
        {
            Errors = new List<Error> { error }
        };
    }
}

public class Result<T> : Result
{
    public T Data { get; set; }
}

最让我烦恼的是,你必须为 Fail 方法指定一个类型,即使 Fail 方法只会导致 T 为 null。

我知道这是一个挑剔的问题,但这是我多年来一直想知道的问题。它的使用很烦人,而且不得不写

Result.Fail<MyDto?>("Some Error Message")
有点误导。如果有人确实有更好的方法,我很想听听。我已经将这个课程转移到打字稿几次只是为了业余项目,它在那里工作得更好。

更新我通过使用 OneOf 取得了一些进展(感谢@Alejandro)

这无法编译,但我可能越来越接近了。

public class Result
{
    //cut for brevity
    public static Result<EmptyResponse> Fail(Error error)
    {
        return new Result<EmptyResponse>
        {
            Errors = new List<Error> { error },
            Data = new EmptyResponse() //Errors here. See error below
        };
    }
}

public class Result<T> : Result
{
    public OneOf<T, EmptyResponse> Data { get; set; }
}

ERROR: Cannot convert source type 'Playground.EmptyResponse' to target type 'OneOf.OneOf<Playground.EmptyResponse,Playground.EmptyResponse>

即使 Data 是 OneOf T 或 EmptyResponse。它仍然需要提供 T 的类型信息。因此,虽然上面的代码无法编译,但是这会

    public static Result<T> Fail<T>(Error error)
    {
        return new Result<T>
        {
            Errors = new List<Error> { error },
            Data = new EmptyResponse()
        };
    }

这基本上又回到了第一个方面。向不需要的 Fail 提供类型信息。

c# unions
1个回答
0
投票

为什么不直接从

Result
工厂方法返回
Fail
呢?或者,您可以在类型上使用模式匹配以获得更实用的体验,并从成功结果中删除
Errors
,就像从失败结果中删除
Data
一样:

https://dotnetfiddle.net/IFYFHj

public interface IResult
{
}

public record SuccessResult : IResult
{
    public static readonly SuccessResult Instance = new();
}

public record SuccessResult<TData>( TData Data ) : SuccessResult;

public record FailureResult : IResult
{
    public static readonly FailureResult Instance = new();
}

public record FailureResult<TError>( IEnumerable<TError> Errors ) : FailureResult;

用途:

var msg = result switch
{
    SuccessResult<int> sri => $"Successful with data {sri.Data}",
    SuccessResult sr => $"Successful with no data",
    FailureResult<int> fri => $"Failed with errors",
    FailureResult fr => $"Failed without errors",
    _ => throw new NotImplementedException( result.GetType().FullName ),
};
© www.soinside.com 2019 - 2024. All rights reserved.