使用FSharpLu在F#中序列化歧视联盟-如何在歧视联盟类型中隐藏属性名称?

时间:2018-12-08 09:26:17

标签: serialization f# discriminated-union

我是F#的新手,有一个任务来序列化受歧视联盟。这本身很简单,您可以对其进行序列化,然后得到一个很好的(丑陋的)情况:fields:节点集。

使用FSharpLu(https://github.com/Microsoft/fsharplu)的紧凑型序列化程序,我们可以将此格式简化为更易于管理的格式,而无需使用Case:Field:节点。 但是,相反,我们获得了被序列化为节点名称的Type的名称。这是不需要的。

如果我有以下类型:

type Entry = {
    id: string
    foo: int
    bar: string
}

type Group = {
    id: string
    entryList: Entry seq
}

type EntryOrGroup =
 | Entry of Entry
 | Group of Group

在输出中,是一个EntryOrGroup数组,我将使每个节点都用其类型名修饰,这是我不想要的。

是否可以隐藏类型名称?但仍然输出所需的json节点?

编辑: 当前输出示例:

[
    {
        Group: {
            id: "firstEntry",
            entryList: [
                {
                id: "foobar",
                foo: 12,
                bar: "something"
                },
                {
                id: "barfoo",
                foo: 13,
                bar: "somethingElse"
                }
            ]
        },
        {
        Entry: {
            id: "foofoobar",
            foo: 16,
            bar: "notSomething"
            }
        }
    }
]

所需输出示例:

[
    {
        {
            id: "firstEntry",
            entryList: [
                {
                id: "foobar",
                foo: 12,
                bar: "something"
                },
                {
                id: "barfoo",
                foo: 13,
                bar: "somethingElse"
                }
            ]
        },
        {
            {
            id: "foofoobar",
            foo: 16,
            bar: "notSomething"
            }
        }
    }
]

Edit2: 我分叉了FSharpLu存储库,并更改了Compact Serializer,使其不再在Discriminated Union中写入对象的开头和对象的结尾。这样可以达到我想要的结果。但是,我现在不知道我该如何在工作中实现它……分叉的仓库是否需要维护太多,对于这个微小的变化值得吗?嗯...

更改来自Line 146 of Compact.fs: 发件人:

        else
        let case, fields = getUnionFields value

        match fields with
        // Field-less union case
        | [||] -> writer.WriteValue(convertName case.Name)
        // Case with single field
        | [|onefield|] ->
            writer.WriteStartObject()
            writer.WritePropertyName(convertName case.Name)
            serializer.Serialize(writer, onefield)
            writer.WriteEndObject()
        // Case with list of fields
        | _ ->
            writer.WriteStartObject()
            writer.WritePropertyName(convertName case.Name)
            serializer.Serialize(writer, fields)
            writer.WriteEndObject()

收件人:

        else
        let case, fields = getUnionFields value

        match fields with
        // Field-less union case
        | [||] -> writer.WriteValue(convertName case.Name)
        // Case with single field
        | [|onefield|] ->
            serializer.Serialize(writer, onefield)
        // Case with list of fields
        | _ ->
            writer.WritePropertyName(convertName case.Name)
            serializer.Serialize(writer, fields)

1 个答案:

答案 0 :(得分:1)

如果您不想编写/维护自定义Json.NET转换器,可以考虑以下几种选择:

1。使用其他一些序列化库

两种选择可让您更好地控制数据的序列化方式:

  1. Thoth.Json.Net
  2. Chiron

2。使用根据需要序列化的数据传输对象

:right

3。取消扭曲并装箱

    type EntryOrGroupDTO = {
        id: string
        foo: int option
        bar: string option
        entryList: Entry seq option
    }

    let dtoData =
        data
        |> Array.map (fun entryOrGroup ->
            match entryOrGroup with
            | Entry entry ->
                { id = entry.id
                  foo = Some entry.foo
                  bar = Some entry.bar
                  entryList = None }
            | Group group ->
                { id = group.id
                  foo = None
                  bar = None
                  entryList = Some group.entryList })

    let settings =
        JsonSerializerSettings(
            NullValueHandling=NullValueHandling.Ignore,
            Converters=[|CompactUnionJsonConverter()|]
        )

    JsonConvert.SerializeObject(dtoData, Formatting.Indented, settings)