简体   繁体   English

使用Json.NET将F#序列化为字符串

[英]Serializing F# Discriminated union as strings with Json.NET

I'm trying to do a one way transform from F#'s discriminated union to strings upon serialization instead of the default `"Case": [value]". Being able to deserialize the value again is not an issue. Maybe possible with Json.NET? 我正在尝试从F#的区分联合转换为字符串序列化而不是默认的“Case”:[value]“。能够再次反序列化值不是问题。也许可以使用Json.NET ?

// Fsharp 4.1.0
open Newtonsoft.Json // 10.0.3

type HowLame =
| PrettyLame
| SuperLame

type Lame = {
    howLame: HowLame;
}

[<EntryPoint>]
let main argv =
    let lame = { howLame = PrettyLame }
    let ser = JsonConvert.SerializeObject(lame)

    // {"soLame":{"Case":"PrettyLame"}} by default
    printfn "%s" ser

    // Desired
    assert (ser = """{"soLame":"PrettyLame"}""")
    0 // return an integer exit code

Creating a custom Json.NET JsonConverter and using it to decorate the discriminated union ("enum style") was enough to get this working the way I wanted. 创建一个自定义的Json.NET JsonConverter并使用它来装饰有区别的联合(“enum style”)足以让它以我想要的方式工作。 A good chunk of this is transliterated from @Brian Rogers answer in C# https://stackoverflow.com/a/22355712/1924257 其中很大一部分是从@Brian Rogers在C# https: //stackoverflow.com/a/22355712/1924257的答案中音译出来的。

open System
open Newtonsoft.Json // 10.0.3
open Newtonsoft.Json.Converters

type ToStringJsonConverter () =
    inherit JsonConverter()
    override this.CanConvert objectType = true;

    override this.WriteJson (writer: JsonWriter, value: obj, serializer: JsonSerializer): unit = 
        writer.WriteValue(value.ToString())

    override this.CanRead = false

    override this.ReadJson (reader: JsonReader, objectType: Type, existingValue: obj, serializer: JsonSerializer) : obj =
        raise (new NotImplementedException());

[<JsonConverter(typeof<ToStringJsonConverter>)>]
type HowLame =
| PrettyLame
| SuperLame

type Lame = {
    howLame: HowLame
}

[<EntryPoint>]
let main argv =
    let lame = { howLame = PrettyLame }
    let ser = JsonConvert.SerializeObject(lame)

    // {"howLame":"PrettyLame"}
    printfn "%s" ser

    0 // return an integer exit code

If you are willing to make the DU an enum (by specifying explicit values, which probably is OK since there is no 'payload'), you can use the standard StringEnumConverter : 如果您愿意将DU设为enum(通过指定显式值,因为没有'payload'可能没有问题),您可以使用标准的StringEnumConverter

#r "../packages/Newtonsoft.Json/lib/net45/Newtonsoft.Json.dll"
open Newtonsoft.Json

type HowLame = PrettyLame=0 | SuperLame=1
type Lame = { howLame: HowLame; }

// in contrast to DUs, enums must be qualified, i.e. Enum.Value
let lame = { howLame = HowLame.PrettyLame }

let settings = JsonSerializerSettings()
settings.Converters.Add(Converters.StringEnumConverter())

let ser = JsonConvert.SerializeObject(lame, settings)
// val ser : string = "{"howLame":"PrettyLame"}"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM