扩展方法返回 <T> 而不是结果 <T>

Extension Method Returning <T> Instead of Result<T>

我正在研究 Vladimir Khorikov 的 Result class 以及如何使用它来链接结果操作。

可以找到他们的原创文章here

他们原来的 Result class 代码可以找到 here.

我编辑的Resultclass代码如下:

public class Result
{
    private bool _isSuccess;
    private string _errorMsg = "";

    public bool IsSuccess()
    {
        return _isSuccess;
    }

    public bool IsFailure()
    {
        return !_isSuccess;
    }

    public string ErrorMsg()
    {
        return _errorMsg;
    }

    public Result(bool isSuccess, string errorMsg)
    {
        bool errorMsgIsEmpty = string.IsNullOrEmpty(errorMsg);

        if (isSuccess && !errorMsgIsEmpty)
        {
            throw new Exception("cannot have error message for successful result");
        }
        else if (!isSuccess && errorMsgIsEmpty)
        {
            throw new Exception("must have error message for unsuccessful result");
        }

        _isSuccess = isSuccess;

        if (!errorMsgIsEmpty)
        {
            _errorMsg = errorMsg;
        }
    }

    public static Result Fail(string errorMsg)
    {
        return new Result(false, errorMsg);
    }

    public static Result<T> Fail<T>(string errorMsg)
    {
        return new Result<T>(default(T), false, errorMsg);
    }

    public static Result OK()
    {
        return new Result(true, "");
    }

    public static Result<T> OK<T>(T value)
    {
        return new Result<T>(value, true, "");
    }

    public static Result Combine(params Result[] results)
    {
        foreach (Result result in results)
        {
            if (result.IsFailure())
            {
                return result;
            }
        }

        return OK();
    }
}

public class Result<T> : Result
{
    private T _value;

    public T Value()
    {
        return _value;
    }

    public Result(T value, bool isSuccess, string errorMsg) : base(isSuccess, errorMsg)
    {
        _value = value;
    }
}

我正在进行以下测试 class:

public class Fruit
{
    private string _name = "";
    private StringBuilder _attribs;
    public bool isBad;

    public Fruit(string name)
    {
        _name = name;
        _attribs = new StringBuilder();
    }

    public string Name()
    {
        return _name;
    }

    public string Attribs()
    {
        string attribs = _attribs.ToString();

        if (attribs.Length > 0)
        {
            return attribs.Remove(attribs.Length - 2);
        }

        return attribs;
    }

    public void AddAttrib(string attrib)
    {
        _attribs.Append(attrib + ", ");
    }
}

下面是在Fruit上运行的class:

public class FruitOperator
{
    public static Result<Fruit> AddAttribToFruit(Fruit fruit, string attrib, bool fail)
    {
        if (fail)
        {
            return Result.Fail<Fruit>("failed");
        }

        fruit.AddAttrib(attrib);

        return Result.OK<Fruit>(fruit);
    }

    public static void MarkFruitAsBad(Fruit fruit)
    {
        fruit.isBad = true;
    }
}

我创建了以下 Result 扩展方法来匹配 AddAttribToFruitMarkFruitAsBad 的函数签名:

public static class ResultExtensions
{
    public static Result<T> OnSuccess<T>(this Result<T> result, Func<T, string, bool, Result<T>> func, T val, string str, bool flag)
    {
        if (result.IsFailure())
        {
            return result;
        }

        return func(val, str, flag);
    }

    public static Result<T> OnFailure<T>(this Result<T> result, Action<T> action)
    {
        if (result.IsFailure())
        {
            action(result.Value());
        }

        return result;
    }
}

我的问题是当我尝试在下一个操作中使用 OnSuccess 的结果时:

Fruit fruit = new Fruit("apple");
Result<Fruit> fruitResult = FruitOperator.AddAttribToFruit(fruit, "big", false)
.OnSuccess(FruitOperator.AddAttribToFruit, fruit, "red", true)
.OnFailure(lastFruitResult => FruitOperator.MarkFruitAsBad(lastFruitResult.Value()));

以上,lastFruitResult实际上是Fruit而不是我预期的Result<Fruit>

我的扩展方法签名是否有问题,或者我需要根据我的使用方式进行更改?

您在 OnFailure 中的签名有点错误。将其更改为 OnFailure<T>(this Result<T> result, Action<Result<T>> action).

基本上,Action 是一个带有多个参数的委托。与 Func 的区别在于 Action 不是 return 值。

OnFailure<T>(this Result<T> result, Action<T> action) 将让消费者传递类型为 T 的操作作为输入。在你的情况下 TFruit 因为它实际上是在 AddAttribToFruit 中定义的,因为它 returns Result<Fruit>.

通过将签名更改为: OnFailure<T>(this Result<T> result, Action<Result<T>> action) 它将让消费者创建类型为 Result<T> 的操作,在您的情况下为 Result<Fruit>.

您的 OnFailure 可能看起来像这样:

   public static Result<T> OnFailure<T>(this Result<T> result, Action<Result<T>> action)
   {
        if (result.IsFailure())
        {
            action(result); // Note that result is Result<T> and action takes Result<T> as parameter
        }

        return result;
    }

lastFruitResult 将是 Action<here>.

中定义的类型