我是C#中功能性思维方式的新手(嗯...不限于语言)。假设有一种方法:

T LoadRecord<T>(int id)

概念

1.验证

当给出无效输入时,我应该返回类似Either<IEnumerable<ValidationError>, T>的内容。

2.执行

当调用可能抛出的DB/API/...时,我应该返回Either<Exception, T>

3.一些记录或无记录

因为条目可能存在或可能不存在,所以我返回Option<T>

最终签名

如果将以上所有内容结合起来,最终会得到以下结果:
Either<IEnumerable<ValidationError>, Either<Exception, Option<T>> LoadRecord<T>(int id)

我可以介绍以下类型:
  • Validation<T>(〜: Either<IEnumerable<ValidationError>, T>)
  • Result<T>(〜: Either<Exception, T>)

  • 现在,我方法的签名如下所示:
    Validation<Result<Option<T>>> LoadRecord<T>(int id)
    

    用法
    return LoadRecord<User>(1).Match(
               vl => BadRequest(),
               vr => vr.Match(
                         el => StatusCode(500),
                         er => er.Some(u => Ok(u))
                                 .None(NotFound());
    

    强制执行
    try
    {
        var u = LoadRecord<User>(id);
        if (u == null)
        {
            return NotFound();
        }
    
        return Ok(u);
    }
    catch (ValidationException)
    {
        return BadRequest();
    }
    catch (Exception)
    {
        return StatusCode(500);
    }
    

    问题

    如您所见,方法的签名仍然很奇怪-乍一看,它给您“验证”,但是我真的在要求T。用法看起来也不是很漂亮,但确实比命令式的更为简洁。

    这是正确的方法吗?有没有办法提高代码的签名/可读性?

    最佳答案

  • 是的,是的。根据涉及的复杂性,一个现代的(我猜是C#7)元组可能就足够了:(bool failed, T result)。局限性在于,没有方法负责正确的链接-按照Haskell的fmap编码-您的容器(更好的说,但理论上不太正确-您的FunctorMonad很少见)。
  • Either<IEnumerable<ValidationError>, Either<Exception, Option<T>> LoadRecord<T>(int id)-不。观察您的签名:TFail 一样,您会得到IEnumerable<ValidationError>Exception;因此,从技术上讲,您需要在那里使用Exception | IEnumerable<ValidationError>类型,以为在C#中实现需要花很多的工夫。 Option<T>部分也是如此,它表示成功的结果:您不需要返回IOption;即使存在,您的实现也会负责解包成功的结果并吐出T或通过TFail机制报告Either错误。结论:是的,容器很棒,但要避免无尽的嵌套:有时间包装东西,有时间拆开它们:感受一下
  • 最后但并非最不重要:异常处理应委派给容器本身。 Rx是一个很好的例子:它询问您onError: Action<Exception> lambda,捕获异常时将调用该lambda。因此,您可以让客户自定义所需的行为,而不是一次对其进行硬编码。不仅如此,因为您的特定示例是特定的,所以IOption是一种处理错误的方法,因此在您的特殊情况下-,但不是一般规则-不需要onError:只需吞下一个异常并返回Nothing即可。
  • 关于C#FP : Validation and execution with error handling functional way - space for improvement?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51865761/

    10-11 10:50