使用 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.使用其他一些序列化库
可以让您更好地控制数据序列化方式的两种选择:
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)
我是 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.使用其他一些序列化库
可以让您更好地控制数据序列化方式的两种选择:
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)