Как использовать JSON.NET для десериализации в вложенный / рекурсивный словарь и список?
Мне нужно десериализовать сложную блочную JSON в стандартные .NET-контейнеры для использования в коде, который не знает JSON . Он ожидает, что все будет в стандартных типах .NET, в частности Dictionary [string, object] или List [object], где «объект» может быть примитивным или recurse (словарь или список).
Я не могу использовать статический тип для сопоставления результатов, а JObject / JToken не подходит. В идеале, может быть каким-то образом (через Контракты, возможно?), Чтобы преобразовать raw JSON в основные .NET-контейнеры.
Я искал все, чтобы уговорить десериализатор JSON.NET на создание этих простых типов, когда он сталкивается с «{}» или «[]», но с небольшим успехом.
- Сериализация - readObject writeObject переопределяет
- Дезерминирование полиморфных типов с jacksonом
- Библиотека Jackson JSON: как создать экземпляр classа, содержащего абстрактные поля
- Сериализация Java - java.io.InvalidClassException локальный class несовместим
- Полиморфизм в аннотациях jacksonа: использование @JsonTypeInfo
Любая помощь ценится!
- Уничтожить вложенные JSON в объекты C #
- Как сериализовать объект, который включает BufferedImages
- Удаление десериализации JSON в .NET-объект с использованием Newtonsoft (или LINQ to JSON, возможно?)
- Дезаминирование гетерогенного массива JSON в ковариантный список с использованием JSON.NET
- Дессериализация данных JSON на C # с использованием JSON.NET
- Разбор большого json-файла в .NET.
- Отключить JSON в существующий объект (Java)
- JSON для экземпляра classа TypeScript?
Если вы просто хотите использовать общий метод, который может обрабатывать любой произвольный JSON и преобразовывать его во вложенную структуру обычных типов .NET (примитивы, списки и словари), вы можете использовать API LINQ to JSON API JSON.Net для этого:
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() .ToDictionary(prop => prop.Name, prop => ToObject(prop.Value)); case JTokenType.Array: return token.Select(ToObject).ToList(); default: return ((JValue)token).Value; } } }
Вы можете вызвать метод, как показано ниже. obj
будет либо содержать Dictionary
, List
, либо примитив в зависимости от того, с каким JSON вы начали.
object obj = JsonHelper.Deserialize(jsonString);
Один из способов десериализации строки json рекурсивно в словари и списки с JSON.NET – это создание пользовательского json-конвертерного classа, который происходит из абстрактного classа JsonConverter, предоставляемого JSON.NET.
Именно в вашем производном JsonConverter
вы помещаете реализацию того, как объект должен быть записан в json и из него.
Вы можете использовать свой JsonConverter
следующим образом:
var o = JsonConvert.DeserializeObject>(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; 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
Вот эквивалент в 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 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 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) = 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>).IsAssignableFrom t override __.WriteJson (writer:JsonWriter, value: obj, _:JsonSerializer) = writeValue writer value override __.ReadJson (reader:JsonReader, _: Type, _:obj, _:JsonSerializer) = readValue reader
Вы не можете делать то, что я просил. По крайней мере, насколько я могу судить после MUCH исследований. Мне пришлось отредактировать источник Json.NET.
Я люблю AutoMapper и, похоже, думаю, что он решает многие проблемы … как этот …
почему бы просто не позволить JSON.NET преобразовать эту вещь во все, что она хочет … и использовать AutoMapper для сопоставления ее с объектом, который вы действительно хотите.
Если производительность не является первостепенной, этот дополнительный шаг должен стоить того, чтобы уменьшить сложность и возможность использовать нужный сериализатор.
Вы можете иметь полный контроль над сериализацией типа с помощью пользовательского JsonConverter
. Документация по адресу http://james.newtonking.com/projects/json/help/html/T_Newtonsoft_Json_JsonConverter.htm .
Кроме того, согласно этому сообщению в блоге, вам нужно использовать JArray
для списка и JObject
для словаря.