.net - jsonconvert - newtonsoft json serialize c#
¿Cómo uso JSON.NET para deserializar en Diccionario y Lista anidados/recursivos? (5)
Amo AutoMapper y parezco pensar que resuelve muchos problemas ... como este ...
¿Por qué no dejar que JSON.NET convierta la cosa en lo que quiera ... y usar AutoMapper para AutoMapper en el objeto que realmente desea?
A menos que el rendimiento sea primordial, este paso adicional debería valer la pena por la reducción de la complejidad y la capacidad de utilizar el serializador que desee.
Necesito deserializar una burbuja compleja de JSON en contenedores .NET estándar para usar en código que no tenga conocimiento de JSON . Espera que las cosas estén en tipos .NET estándar, específicamente Dictionary [string, object] o List [object] donde "object" puede ser primitivo o recurse (Dictionary o List).
No puedo usar un tipo estático para mapear los resultados y JObject / JToken no encajan. Idealmente, habría alguna forma (¿quizás a través de los contratos?) De convertir JSON sin formato en contenedores .NET básicos.
Busqué por todas partes alguna manera de lograr que el deserializador JSON.NET cree estos tipos simples cuando encuentra "{}" o "[]" pero con poco éxito.
Cualquier ayuda apreciada!
No puedes hacer lo que te pedí. Al menos no tan lejos como puedo decir después de MUCHA investigación. Tuve que editar la fuente de Json.NET.
Puede tener control total sobre la serialización de un tipo utilizando un JsonConverter
personalizado. Documentación en http://james.newtonking.com/projects/json/help/html/T_Newtonsoft_Json_JsonConverter.htm .
Además, de acuerdo con esta publicación de blog necesita usar JArray
para una lista, y JObject
para un diccionario.
Si solo desea un método genérico que pueda manejar cualquier JSON arbitrario y convertirlo en una estructura anidada de tipos regulares .NET (primitivas, listas y diccionarios), puede usar la API LINQ-to-JSON de JSON.Net para hacerlo:
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;
}
}
}
Puede llamar al método como se muestra a continuación. obj
contendrá un Dictionary<string, object>
, List<object>
o primitiva, dependiendo de con qué JSON haya comenzado.
object obj = JsonHelper.Deserialize(jsonString);
Una forma de deserializar json string recursivamente en diccionarios y listas con JSON.NET es crear una clase de convertidor json personalizada que se derive de la clase abstracta JsonConverter
proporcionada por JSON.NET.
Es en su JsonConverter
derivado donde pone la implementación de cómo debe escribirse un objeto JsonConverter
desde json.
Puedes usar tu JsonConverter
personalizado así:
var o = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, new DictionaryConverter());
Este es un JsonConverter personalizado que utilicé con éxito en el pasado para lograr los mismos objetivos que describe en su pregunta:
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); }
}
Aquí está el equivalente en 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