F#,Json,WebApi选项类型的序列化

时间:2015-01-26 13:22:23

标签: f# json.net

我在F#项目中使用记录类型,我正在向C#WebApi项目公开。例如:

type Account = {Amount:float; Number:int; Holder:string}

基于this帖子和this帖子,json正确地进行了序列化。

{"Amount":100.0,"Number":1,"Holder":"Homer"}

但是,当我在记录中添加选项类型时,

type Account = {Amount:float; Number:int; Holder:string option }

json变得脱胶。

{"Amount":100.0,"Number":1,"Holder":{"Case":"Some","Fields":["Homer"]}}

我希望json看起来与非选项类型记录相同,序列化程序足够聪明,可以自动获取值并将它们放入/移出选项类型。

有人为此建立了自定义格式化程序吗?有什么东西我错过了吗?

由于

2 个答案:

答案 0 :(得分:14)

我在另一个答案中尝试了链接转换器,我不喜欢其他不是Option的DU的输出。除此之外,您可能希望选择仅更改Option类型而不是所有DU的行为。

我发现这个转换器只会改变选项类型的行为,以便在None选项上呈现null,否则就是值。可以找到原始代码/作者信息here

open System
open Microsoft.FSharp.Reflection
open Newtonsoft.Json
open Newtonsoft.Json.Converters

type OptionConverter() =
    inherit JsonConverter()

    override x.CanConvert(t) = 
        t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<option<_>>

    override x.WriteJson(writer, value, serializer) =
        let value = 
            if value = null then null
            else 
                let _,fields = FSharpValue.GetUnionFields(value, value.GetType())
                fields.[0]  
        serializer.Serialize(writer, value)

    override x.ReadJson(reader, t, existingValue, serializer) =        
        let innerType = t.GetGenericArguments().[0]
        let innerType = 
            if innerType.IsValueType then (typedefof<Nullable<_>>).MakeGenericType([|innerType|])
            else innerType        
        let value = serializer.Deserialize(reader, innerType)
        let cases = FSharpType.GetUnionCases(t)
        if value = null then FSharpValue.MakeUnion(cases.[0], [||])
        else FSharpValue.MakeUnion(cases.[1], [|value|])

使用转换器与其他答案相同:

let json = JsonConvert.SerializeObject(myObj, new OptionConverter())

答案 1 :(得分:6)

处理选项类型和单一类型区分联合的自定义Json.NET转换器确实存在(或者至少声称,我只测试了选项类型的情况)。它可以找到here

用法:

let act = {Amount= 100.0; Number= 1; Holder= Some "Homer"}
let json = JsonConvert.SerializeObject(act, new IdiomaticDuConverter())