如何将 Validation<string, Unit> 转换为成功时为空的字符串?
Posted
技术标签:
【中文标题】如何将 Validation<string, Unit> 转换为成功时为空的字符串?【英文标题】:How do I convert a Validation<string, Unit> to a string that's empty on success? 【发布时间】:2020-08-05 18:35:55 【问题描述】:我是函数式编程的新手,并且正在尝试在一个非常命令式的代码库中工作,所以我正在尝试编写主要是 FP 的代码,但不能完全。
我必须为下面的方法写一个覆盖...
protected override string CreateEntity(XElement xe)
...其中xe
包含数据库更新所需的两条数据。该方法需要验证xe
的内容,然后进行更新,成功则返回“”,否则返回以竖线分隔的错误列表。
我从语言扩展测试中的credit card validation sample 中得到启发,并编写了一些如下的辅助方法(实现与示例非常相似,因此省略)...
private Validation<string, int> ValidateRegionID(XElement xe)
在示例中,他对这些集合使用了 Apply,如果一切正常,则返回一个 Validation
,这是新的信用卡对象,否则返回一个 Error
。就我而言,如果一切顺利(因为我正在更新数据库,而不是创建新对象),我没有任何东西可以返回,所以到此为止......
Validation<string, Unit> validation = (ValidateRegionID(xe), ValidateClinAppsID(xe))
.Apply((regionID, clinAppsID) =>
// Do the database update (yes, impure code)...
return Unit.Default;
);
我不知道这是否是最好的方法,所以欢迎任何建议。
我更大的问题是下一步该做什么。以下工作,但对我来说看起来不是很优雅或 FP...
return validation.IsFail
? string.Join("|", validation.FailAsEnumerable())
: "";
有更好的方法吗?
【问题讨论】:
【参考方案1】:如果验证失败,您可以简单地抛出异常。 稍后调用您的代码的任何人都可以对其应用异常处理。
另一个选项是发送错误代码而不是消息。在这种情况下,被调用者可以将每个错误代码转换为特定错误。
【讨论】:
感谢您的回复,但正如我所说,我需要覆盖现有方法,因此无法更改调用代码的作用。我必须返回一个字符串,如果一切顺利,该字符串将为空,否则包含管道分隔的错误。 @AvrohomYisroel 在这种情况下你写的没问题,如果你确实需要将错误消息组合在一起,我看不到其他选项。【参考方案2】:代码的最后一部分(格式错误)可以这样完成:
[Fact]
void Test()
Validation<string, Unit> resultFromDatabase = Fail<string, Unit>("error");
var showError1 = string.Join("|", resultFromDatabase.FailToSeq()); // use the fact that FailToSeq() will return empty seq for success
var showError2 = string.Join("|", resultFromDatabase.IfSuccess(Seq<string>())); // explicitly supply a value of the error type (Seq<string>) for success case
var showError3 = resultFromDatabase.Match(_ => "", errors => string.Join("|", errors)); // only call string.Join for errors
选择您最喜欢的变体。如果你想要干净的代码/不要依赖 FailToSeq() 实现在这两种情况下工作,你应该使用Match
或IfSuccess
/IfFail
明确处理这两种情况。
如果你想改进你的整体设计(避免不纯的代码),你可能需要改变一些基本的东西。一个(非常 FP)选项是使用 Free Monad,LanguageExt 取得了进展以使其更容易,但这可能是转换传统 OO 代码库的一大步。见:
https://github.com/louthy/language-ext/releases/tag/3.4.11(使用 CodeGen 的免费 Monad) https://github.com/louthy/language-ext/wiki/Thinking-Functionally:-Application-Architecture
【讨论】:
谢谢。我没有任何理由不想使用FailToSeq()
(我应该有什么理由吗?),这提供了一个简洁的解决方案。我很高兴转向一种非常 FP 的方法,但我正在使用一个非常命令式的大型代码库,以及一个不太热衷于彻底改变的经理。我也因缺乏理解而受到阻碍,尽管随着我的努力,这种情况正在变得更好。再次感谢。
不客气。在本地改进代码是完全没问题的。关于FailToSeq()
:如果您也将其称为“成功”,则会增加两个(小)风险:如果 LanguageExt 中的实现发生更改(例如,禁止对“成功”=> 异常进行此操作),您就是代码中断。我不认为保罗会改变这一点(但似乎这不在单元测试中)。第二个风险是您的代码的读者可能想知道在“成功”情况下到底发生了什么(异常与空结果)。取决于您的上下文,整体可读性...以上是关于如何将 Validation<string, Unit> 转换为成功时为空的字符串?的主要内容,如果未能解决你的问题,请参考以下文章
[TypeScript] Decorator-based Validation using Class Validator
如何将 ko.validation 错误与相关的视图模型字段名称联系在一起
如何使用 Knockout-Validation 将无效项目添加到 observableArray 以使 validObservable 无效