Functional programming 用度量单位构造和解构单例判别并集

Functional programming 用度量单位构造和解构单例判别并集,functional-programming,f#,domain-driven-design,Functional Programming,F#,Domain Driven Design,我有两种类型: 脏传输对象的DTO;)用于反序列化JSON有效负载的 使我的数据在域内保持一致和干净的域 我有两个函数将记录从一个空间转换到另一个空间。我想使用度量单位,但解决方案似乎有点粗糙。我想知道实施这项计划的其他选择是什么 模块MyApp.Api.Dto 开放系统 [] 类型提要= { 体积:十进制 入口时间:日期时间 } 模块MyApp.Api.Domain [] ml型 FeedVolume类型=十进制的专用FeedVolume 模块进料量= let值(进料体积f)=f 让我们

我有两种类型:

  • 脏传输对象的DTO;)用于反序列化JSON有效负载的
  • 使我的数据在域内保持一致和干净的域
我有两个函数将记录从一个空间转换到另一个空间。我想使用度量单位,但解决方案似乎有点粗糙。我想知道实施这项计划的其他选择是什么

模块MyApp.Api.Dto
开放系统
[]
类型提要=
{
体积:十进制
入口时间:日期时间
}
模块MyApp.Api.Domain
[]
ml型
FeedVolume类型=十进制的专用FeedVolume
模块进料量=
let值(进料体积f)=f
让我们创建dec=
如果dec FeedVolume.create
让我来!entryTime=dto.entryTime |>entryTime.create
返回{
体积=体积
入口时间=入口时间
}
}
错误:

Type mismatch. Expecting a
    'decimal -> Result<'a,string>'    
but given a
    'decimal<ml> -> Result<FeedVolume,string>'    
The type 'decimal' does not match the type 'decimal<ml>'
类型不匹配。期待

'decimal->Result如果您使用Newtonsoft反序列化JSON,我只会将度量单位放在DTO定义中。您的
create
函数应该验证域的不变量,而不是单元。如果要从原始基元创建一个已验证的域类型,而不使用任何单位,则应该有一个单独的函数,如
unsafeCreate
,用于强制基元使用正确的单位

下面是一个使用Newtonsoft将JSON与DTO中的单元反序列化的示例:

[]类型kg
[]类型ml
类型DtoWithUnitsOfMeasure=
{ 
体积:十进制
重量:十进制
}
[]
让带有度量单位的DTO反序列化为度量值()=
让json=“”{“体积”:3.2348,“重量”:0.682}”“”
让dto=json |>JsonConvert.DeserializeObject
dto.体积|>应等于3.2348M
dto.重量|>应等于0.682M

这个测试对我来说是通过的。

如果您使用Newtonsoft对JSON进行反序列化,我只会在DTO定义中添加度量单位。您的
create
函数应该验证域的不变量,而不是单元。如果要从原始基元创建一个已验证的域类型,而不使用任何单位,则应该有一个单独的函数,如
unsafeCreate
,用于强制基元使用正确的单位

下面是一个使用Newtonsoft将JSON与DTO中的单元反序列化的示例:

[]类型kg
[]类型ml
类型DtoWithUnitsOfMeasure=
{ 
体积:十进制
重量:十进制
}
[]
让带有度量单位的DTO反序列化为度量值()=
让json=“”{“体积”:3.2348,“重量”:0.682}”“”
让dto=json |>JsonConvert.DeserializeObject
dto.体积|>应等于3.2348M
dto.重量|>应等于0.682M

这个测试对我来说是通过的。

问题是如何从
float
中提取原语
float
。您可以强制转换:
let value(FeedVolume f)=float f
。这里有很多其他代码和标题,但我很确定它们与您的实际问题无关,除非您真的要求代码审查。IMHO,最好将转换尽可能向上移动调用链。因此,使用
dto.volume*1 |>FeedVolume.create
问题是如何从
float
中提取原语
float
。您可以强制转换:
let value(FeedVolume f)=float f
。这里有很多其他代码和标题,但我很确定它们与您的实际问题无关,除非您真的要求代码审查。IMHO,最好将转换尽可能向上移动调用链。所以使用
dto.volume*1>FeedVolume.create