【问题标题】:F#, Json, WebApi Serialization of Option Types选项类型的 F#、Json、WebApi 序列化
【发布时间】:2015-01-26 13:22:22
【问题描述】:

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

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 看起来与非选项类型记录相同,序列化程序足够聪明,可以自动获取值并将它们放入/取出选项类型。

有没有人为此构建了自定义格式化程序?有什么我遗漏的OOB吗?

谢谢

【问题讨论】:

    标签: f# json.net


    【解决方案1】:

    我尝试了另一个答案中链接的转换器,但我不喜欢其他不是 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())
    

    【讨论】:

      【解决方案2】:

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

      用法:

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

      【讨论】:

      • 如何将它添加到 C# 项目中的 WebApiConfig?有没有办法将转换器添加到 DefaultContractResolver?
      • NM -> 明白了。 formatter.SerializerSettings.Converters.Add(new IdiomaticDuConverter());
      猜你喜欢
      • 2023-04-11
      • 1970-01-01
      • 2014-05-12
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      • 1970-01-01
      • 2018-09-01
      • 1970-01-01
      相关资源
      最近更新 更多