gpt4 book ai didi

json - 通过 Json.Net 反序列化 F# Map

转载 作者:行者123 更新时间:2023-12-04 18:42:44 26 4
gpt4 key购买 nike

我有一个简单的问题:是否可以从 解析 F# Map 类型? ?因为当我尝试它时(使用 F# Map<string, string> ),它很容易序列化并且看起来必须如此,但是当我尝试反序列化时它会抛出异常。

Newtonsoft.Json.JsonSerializationException: Unable to find a default constructor to use for type Microsoft.FSharp.Collections.FSharpMap`2[System.Int32,System.String]. Path '1', line 2, position 7.
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewDictionary (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonDictionaryContract contract, System.Boolean& createdFromNonDefaultConstructor) [0x00000] in <filename unknown>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x00000] in <filename unknown>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x00000] in <filename unknown>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType, Boolean checkAdditionalContent) [0x00000] in <filename unknown>:0

它正在从经典反序列化:

Map.ofList [ ("1", "one"); ("2", "two"); ("3", "three") ]

生成的 JSON 看起来像 C# 字典

{
"1": "one",
"2": "two",
"3": "three"
}

它在没有设置的情况下进行序列化(仅缩进)。那么是否可以对其进行序列化,或者是否有一些可行的解决方法?

谢谢回答

最佳答案

您可以制作自己的转换器来执行此操作。这是很多反射和构造适当的泛型类型,但它可以完成。

您首先反序列化为 Dictionary<Key, Val> ,然后创建并填充 List<Tuple<Key, Val>>通过反射手动(因为 Map 构造函数需要 Tuples ,而不是 KeyValuePairs ),然后最后将其传递给 Map构造函数。

不确定是否有更简单的方法,但这是我想出的:

open System
open System.Collections
open System.Collections.Generic
open Newtonsoft.Json

let mapConverter = {
new JsonConverter() with

override x.CanConvert(t:Type) =
t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<Map<_, _>>

override x.WriteJson(writer, value, serializer) =
serializer.Serialize(writer, value)

override x.ReadJson(reader, t, _, serializer) =
let genArgs = t.GetGenericArguments()
let generify (t:Type) = t.MakeGenericType genArgs
let tupleType = generify typedefof<Tuple<_, _>>
let listType = typedefof<List<_>>.MakeGenericType tupleType
let create (t:Type) types = (t.GetConstructor types).Invoke
let list = create listType [||] [||] :?> IList
let kvpType = generify typedefof<KeyValuePair<_, _>>
for kvp in serializer.Deserialize(reader, generify typedefof<Dictionary<_, _>>) :?> IEnumerable do
let get name = (kvpType.GetProperty name).GetValue(kvp, null)
list.Add (create tupleType genArgs [|get "Key"; get "Value"|]) |> ignore
create (generify typedefof<Map<_, _>>) [|listType|] [|list|]
}

拥有转换器后,只需将其传递到 DeserializeObject方法和 JsonConvert将在适当的地方使用它。
let str = JsonConvert.SerializeObject (Map<_, _> [333, 1234])
JsonConvert.DeserializeObject<Map<int, int>>(str, mapConverter)

这样做的好处是,如果您在 Map 的位置有一个大/深的记录。只是一个字段,然后它也可以使用它 - 您不必更改记录结构即可使用 Dictionaries只是为了支持序列化。

关于json - 通过 Json.Net 反序列化 F# Map,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21747666/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com