.net 当编译器坚持它不是';不可能?
我们的项目混合了C#和F#与ASP.NET核心。ASP.NET核心默认为Newtonsoft,用于在任何地方进行序列化/反序列化,而swagger文档生成(nswag)也依赖于类似CLI(可变)的DTO来生成正确的类型 我们的DTO在F#中定义如下:.net 当编译器坚持它不是';不可能?,.net,f#,null,json.net,optional,.net,F#,Null,Json.net,Optional,我们的项目混合了C#和F#与ASP.NET核心。ASP.NET核心默认为Newtonsoft,用于在任何地方进行序列化/反序列化,而swagger文档生成(nswag)也依赖于类似CLI(可变)的DTO来生成正确的类型 我们的DTO在F#中定义如下: [] 类型查询= {状态:字符串 偏移量:int 限制:int} 这使得Newtonsoft序列化和nswag生成swagger文档变得非常简单 但是。。!我对空/选项“不匹配”感到非常困难。C#/Newtonsoft/NSwag坚持使用null
[]
类型查询=
{状态:字符串
偏移量:int
限制:int}
这使得Newtonsoft序列化和nswag生成swagger文档变得非常简单
但是。。!我对空/选项“不匹配”感到非常困难。C#/Newtonsoft/NSwag坚持使用null
,并且不会理解F#的选项
。因此,在我的F#中,我必须检查空值并将其转换为选项;当从域转换回DTO时,还可以将我的选项转换回null
但是F#坚持认为null是不可能的,甚至不允许我检查:编译器给了我:“类型{…}没有'null'作为正确的值”。但事实是,运行时是空的,因为Newtonsoft就是这样工作的。Newtonsoft似乎是.NET标准,所以我不认为使用其他东西是可行的
即使F#认为它不可能为null,我怎么能检查null呢?克服这一问题的一个简单方法(通常)是在检查null之前将值框起来
让isReallyNull value=value |>box |>isNull
然后,您可以在正常逻辑中检查Newtonsoft返回的对象实例:
if dto |> isReallyNull
then None
else Some dto
下面是一个完整的示例,使用Unchecked.defaultof
为编译器说不能为null的类型生成null值:
[<CLIMutable>]
type MyDto =
{
Status: string
Offset: int
Limit: int
}
let isReallyNull value = value |> box |> isNull
let dto = Unchecked.defaultof<MyDto>
// if dto |> isNull (* Compiler complains that MyDto does not have null as a proper value *)
if dto |> isReallyNull
then printfn "The DTO is null"
else printfn "The DTO is non-null"
[]
类型MyDto=
{
状态:字符串
偏移量:int
限制:int
}
让isReallyNull值=值|>框|>isNull
设dto=Unchecked.defaultof
//如果dto |>isNull(*编译器抱怨MyDto没有将null作为正确的值*)
如果dto |>isReallyNull
然后打印fn“DTO为空”
else printfn“DTO为非空”
正如Aaron所建议的,如果dto是一种记录类型,那么您需要执行以下操作:
let optionalValue = dto |> box |> Option.ofObj
现在没有时间给出一个完整的答案,但是有你需要的答案。TL;DR:对您的类型使用
[]
属性。您是否确实尝试过选项
?最后我检查了一下,JSON.NET确实支持它。我尝试了这个选项,它使最可怕的JSON变得可以想象(仍然)。你确定它适合你(开箱即用)吗@rmunn:我已经尝试过使用[],但它不允许:“记录、联合、缩写和结构类型不能有'AllowNullLiteral'属性”也没有时间给出完整的答案,但是一个经常使用的实用程序是FSharpLU.jsonSorry,我认为如果DTO类型是F#Record,这将不起作用。如果不先将其装箱,您将遇到与OP相同的问题。如果您在我上面发布的示例中通过添加行let maybeDto=dto |>Option.ofObj
,尝试此操作,您将得到编译器错误,说明MyDto没有将null作为正确的值
。请注意,使用AllowNullLiteral反序列化到类中的所有操作都与您预期的一样有效。无需告诉编译器它不明白发生了什么:)
let optionalValue = Option.ofObj dto
let optionalValue = dto |> box |> Option.ofObj