加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-16 18:40:58 所属栏目:百科 来源:网络整理
导读:我有一个简单的问题:是否可以从 json解析F#Map类型?因为当我尝试它时(使用F#Map string,string),它很容易序列化并且它看起来如何,但是当我尝试反序列化时它会引发异常. Newtonsoft.Json.JsonSerializationException: Unable to find a default constructor
我有一个简单的问题:是否可以从 json解析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.Object existingValue) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader,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只是一个字段,那么它也可以使用它 – 你不必改变你的记录结构使用词典只是为了支持序列化.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读