使用 FSharpLu 在 F# 中序列化可辨别联合体 - 如何从可辨别联合体类型中隐藏 属性 名称?

Serializing Discriminated Union in F# using FSharpLu - How do i hide property name from Discriminated Union Types?

我是 F# 的新手,有一个任务是序列化一个可区分的联合。这本身很简单,你可以序列化它,你会得到一个很好的(丑陋的)案例: fields: set of nodes.

使用 FSharpLu (https://github.com/Microsoft/fsharplu) 的 Compact Serializer,我们可以将其简化为更易于管理的格式,无需大小写:字段:节点。 但是,相反,我们得到的是被序列化为节点名称的类型的名称。这不是想要的。

如果我有这样的类型:

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"
            }
        }
    }
]

编辑2: 我分叉了 FSharpLu 存储库,并更改了 Compact Serializer 以不再在可区别联合中写入对象的开头和结尾。这实现了我正在寻找的结果。但是,我现在不知道如何在我的工作中实现它……分叉的回购是否太多而无法维护,这个微小的变化值得吗?嗯...

更改来自 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)

如果您不想 write/maintain 自定义 Json.NET 转换器,可以考虑以下几个替代方案:

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

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

  1. Thoth.Json.Net
  2. Chiron

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

    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)

3。展开和框

    let objData =
        data
        |> Array.map (fun entryOrGroup ->
            match entryOrGroup with
            | Entry entry -> box entry
            | Group group -> box group)


    JsonConvert.SerializeObject(objData, Formatting.Indented)