如何使用JSON.NET反序列化为嵌套/recursionDictionary和List?

我需要将复杂的JSON blob反序列化为标准的.NET容器,以便在不知道JSON的代码中使用。 它期望的东西是标准的.NETtypes,特别是Dictionary [string,object]或List [object],其中“object”可以是原始的或recursion的(Dictionary或List)。

我不能使用静态types来映射结果,JObject / JToken不适合。 理想情况下,会有一些方法(通过契约)来将原始的JSON转换成基本的.NET容器。

我已经search过任何方式来哄JSON.NET解串器创build这些简单的types,当它遇到“{}”或“[]”,但很less成功。

任何帮助感激!

如果您只是想要一个可以处理任意JSON并将其转换为常规.NETtypes(基本types,列表和字典)的嵌套结构的generics方法,则可以使用JSON.Net的LINQ-to-JSON API来执行此操作:

using System.Linq; using Newtonsoft.Json.Linq; public static class JsonHelper { public static object Deserialize(string json) { return ToObject(JToken.Parse(json)); } private static object ToObject(JToken token) { switch (token.Type) { case JTokenType.Object: return token.Children<JProperty>() .ToDictionary(prop => prop.Name, prop => ToObject(prop.Value)); case JTokenType.Array: return token.Select(ToObject).ToList(); default: return ((JValue)token).Value; } } } 

您可以调用该方法如下所示。 obj将包含一个Dictionary<string, object>List<object>或原语,具体取决于您开始的JSON。

 object obj = JsonHelper.Deserialize(jsonString); 

使用JSON.NETrecursion地将string反序列化为字典和列表的一种方法是创build一个从JsonConverter提供的JsonConverter抽象类派生的自定义JSON转换器类。

这是在你的派生JsonConverter你把实施如何一个对象应该写入和从JSON。

你可以像这样使用你的自定义JsonConverter

 var o = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, new DictionaryConverter()); 

以下是我在过去成功使用的一个自定义JsonConverter,以实现与您在问题中概述的目标相同的目标:

 public class DictionaryConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { this.WriteValue(writer, value); } private void WriteValue(JsonWriter writer, object value) { var t = JToken.FromObject(value); switch (t.Type) { case JTokenType.Object: this.WriteObject(writer, value); break; case JTokenType.Array: this.WriteArray(writer, value); break; default: writer.WriteValue(value); break; } } private void WriteObject(JsonWriter writer, object value) { writer.WriteStartObject(); var obj = value as IDictionary<string, object>; foreach (var kvp in obj) { writer.WritePropertyName(kvp.Key); this.WriteValue(writer, kvp.Value); } writer.WriteEndObject(); } private void WriteArray(JsonWriter writer, object value) { writer.WriteStartArray(); var array = value as IEnumerable<object>; foreach (var o in array) { this.WriteValue(writer, o); } writer.WriteEndArray(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return ReadValue(reader); } private object ReadValue(JsonReader reader) { while (reader.TokenType == JsonToken.Comment) { if (!reader.Read()) throw new JsonSerializationException("Unexpected Token when converting IDictionary<string, object>"); } switch (reader.TokenType) { case JsonToken.StartObject: return ReadObject(reader); case JsonToken.StartArray: return this.ReadArray(reader); case JsonToken.Integer: case JsonToken.Float: case JsonToken.String: case JsonToken.Boolean: case JsonToken.Undefined: case JsonToken.Null: case JsonToken.Date: case JsonToken.Bytes: return reader.Value; default: throw new JsonSerializationException (string.Format("Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType)); } } private object ReadArray(JsonReader reader) { IList<object> list = new List<object>(); while (reader.Read()) { switch (reader.TokenType) { case JsonToken.Comment: break; default: var v = ReadValue(reader); list.Add(v); break; case JsonToken.EndArray: return list; } } throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>"); } private object ReadObject(JsonReader reader) { var obj = new Dictionary<string, object>(); while (reader.Read()) { switch (reader.TokenType) { case JsonToken.PropertyName: var propertyName = reader.Value.ToString(); if (!reader.Read()) { throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>"); } var v = ReadValue(reader); obj[propertyName] = v; break; case JsonToken.Comment: break; case JsonToken.EndObject: return obj; } } throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>"); } public override bool CanConvert(Type objectType) { return typeof(IDictionary<string, object>).IsAssignableFrom(objectType); } } 

这里是f#的等价物:

 type IDictionaryConverter() = inherit JsonConverter() let rec writeValue (writer: JsonWriter) (value: obj) = let t = JToken.FromObject(value) match t.Type with | JTokenType.Object -> writeObject writer value | JTokenType.Array -> writeArray writer value | _ -> writer.WriteValue value and writeObject (writer: JsonWriter) (value: obj) = writer.WriteStartObject () let obj = value :?> IDictionary<string, obj> for kvp in obj do writer.WritePropertyName kvp.Key writeValue writer kvp.Value writer.WriteEndObject () and writeArray (writer: JsonWriter) (value: obj) = writer.WriteStartArray () let array = value :?> IEnumerable<obj> for o in array do writeValue writer o writer.WriteEndArray () let rec readValue (reader: JsonReader) = while reader.TokenType = JsonToken.Comment do if reader.Read () |> not then raise (JsonSerializationException("Unexpected token when reading object")) match reader.TokenType with | JsonToken.Integer | JsonToken.Float | JsonToken.String | JsonToken.Boolean | JsonToken.Undefined | JsonToken.Null | JsonToken.Date | JsonToken.Bytes -> reader.Value | JsonToken.StartObject -> readObject reader Map.empty | JsonToken.StartArray -> readArray reader [] | _ -> raise (JsonSerializationException(sprintf "Unexpected token when reading object: %O" reader.TokenType)) and readObject (reader: JsonReader) (obj: Map<string, obj>) = match reader.Read() with | false -> raise (JsonSerializationException("Unexpected end when reading object")) | _ -> reader.TokenType |> function | JsonToken.Comment -> readObject reader obj | JsonToken.PropertyName -> let propertyName = reader.Value.ToString () if reader.Read() |> not then raise (JsonSerializationException("Unexpected end when reading object")) let value = readValue reader readObject reader (obj.Add(propertyName, value)) | JsonToken.EndObject -> box obj | _ -> raise (JsonSerializationException(sprintf "Unexpected token when reading object: %O" reader.TokenType)) and readArray (reader: JsonReader) (collection: obj list) = match reader.Read() with | false -> raise (JsonSerializationException("Unexpected end when reading array")) | _ -> reader.TokenType |> function | JsonToken.Comment -> readArray reader collection | JsonToken.EndArray -> box collection | _ -> collection @ [readValue reader] |> readArray reader override __.CanConvert t = (typeof<IDictionary<string, obj>>).IsAssignableFrom t override __.WriteJson (writer:JsonWriter, value: obj, _:JsonSerializer) = writeValue writer value override __.ReadJson (reader:JsonReader, _: Type, _:obj, _:JsonSerializer) = readValue reader 

你不能做我所问的。 至less在我做了很多研究之后,我还没有看出来。 我不得不编辑Json.NET的来源。

我喜欢AutoMapper,似乎认为它解决了许多问题…就像这个…

为什么不只是让JSON.NET转换成任何想要的东西…并使用AutoMapper将其映射到您真正想要的对象中。

除非性能是最重要的,否则这个额外的步骤应该是值得的,因为它可以降低复杂性,并且可以使用所需的序列化程序。

您可以通过使用自定义的JsonConverter完全控制types的序列化。 文档在http://james.newtonking.com/projects/json/help/html/T_Newtonsoft_Json_JsonConverter.htm

此外,根据这个博客文章,你需要使用JArray的一个名单,和JObject的字典。