Я изучаю класс Result
Владимира Хорикова и как его можно использовать для цепочки результатов.
Их оригинальную статью можно найти здесь .
Их оригинальный Result
код класса можно найти здесь .
Мои отредактированные коды класса Result
следующие:
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;
}
}
Я работаю со следующими класс тестирования:
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
:
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
методы расширения для соответствия сигнатурам функций AddAttribToFruit
и MarkFruitAsBad
:
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
на самом деле a Fruit
вместо ожидаемого Result<Fruit>
.
Что-то не так с моими сигнатурами метода расширения или есть что-то, что мне нужно изменить в зависимости от того, как я их использую?