Zde*_*něk 6 c# functional-programming optional either
我是C#中功能性思维方式的新手(嗯......不仅限于语言).让我们说有方法:
T LoadRecord<T>(int id)
Run Code Online (Sandbox Code Playgroud)
当给出无效输入时,我应该返回类似的内容Either<IEnumerable<ValidationError>, T>.
当调用可能抛出的DB/API/...时,我应该返回Either<Exception, T>.
因为入境可能存在,也可能不存在,我正在回归Option<T>.
如果你将上述所有内容结合起来,你最终会得到:
Either<IEnumerable<ValidationError>, Either<Exception, Option<T>> LoadRecord<T>(int id)
Run Code Online (Sandbox Code Playgroud)
我可以介绍如下类型:
Validation<T>(〜: Either<IEnumerable<ValidationError>, T>)Result<T>(〜: Either<Exception, T>)现在,我的方法的签名看起来像:
Validation<Result<Option<T>>> LoadRecord<T>(int id)
Run Code Online (Sandbox Code Playgroud)
return LoadRecord<User>(1).Match(
vl => BadRequest(),
vr => vr.Match(
el => StatusCode(500),
er => er.Some(u => Ok(u))
.None(NotFound());
Run Code Online (Sandbox Code Playgroud)
try
{
var u = LoadRecord<User>(id);
if (u == null)
{
return NotFound();
}
return Ok(u);
}
catch (ValidationException)
{
return BadRequest();
}
catch (Exception)
{
return StatusCode(500);
}
Run Code Online (Sandbox Code Playgroud)
你可以看到方法的签名仍然很奇怪 - 乍一看它给你"验证",但我真的要求T.用法也不是很漂亮,但确实比命令式更简洁.
这是正确的方法吗?有没有办法如何提高代码的签名/可读性?
(bool failed, T result):限制是没有方法负责根据fmapHaskell 正确链接你的容器(更好的说法是,但理论上不完全正确 - 你的Functors,以及不太常见的情况下,你的Monads)。Either<IEnumerable<ValidationError>, Either<Exception, Option<T>> LoadRecord<T>(int id)- 不。观察您的签名:对于TFail,您要么得到IEnumerable<ValidationError>或Exception;因此,从技术上讲,您需要一个Exception | IEnumerable<ValidationError>类型,认为在C#. 这同样适用于Option<T>代表成功结果的部分:不需要IOption返回;即使它在那里,您的实现也负责解开成功的结果并只是吐出,或通过该机制T报告错误。结论是:是的,容器很棒,但要避免无休止的嵌套:有时间包装东西,也有时间打开它们:感受那一刻。TFailEitherRx是一个很好的例子:它要求您提供onError: Action<Exception>lambda,当捕获异常时会调用该 lambda。因此,您可以让客户自定义所需的行为,而不是一次对其进行硬编码。更重要的是,由于您的特定示例是特定的,IOption这是一种处理错误的方法,因此在您的特定情况下 -但不是一般规则-onError不需要:只需吞下异常并 return Nothing。