c# - La lista de deserialización de Json.net da elementos duplicados
(2)
Encontré un problema similar con una causa raíz diferente. Estaba serializando y deserializando una clase que se veía así:
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
public class AppointmentRevision
{
public List<Attendee> Attendees { get; set; }
}
Cuando serialicé esto, CurrentRevision también se serializó. No estoy seguro de cómo, pero cuando estaba deserializando, mantenía correctamente una instancia única de AppointmentRevision, pero creaba duplicados en la lista de asistentes. La solución fue usar el atributo JsonIgnore en la propiedad CurrentRevision.
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
[JsonIgnore]
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
Acabo de comenzar a usar Newtonsoft.Json (Json.net). En mi primera prueba simple, me encontré con un problema al deserializar listas genéricas. En el siguiente ejemplo de código, serializo un objeto que contiene tres tipos de listas de enteros simples (propiedad, miembro var y matriz).
El json resultante se ve bien (las listas se convierten en json-arrays). Sin embargo, cuando deserializo el json a un nuevo objeto del mismo tipo, todos los elementos de la lista se duplican, espere la matriz. Lo he ilustrado al serializarlo por segunda vez.
Después de buscar, he leído que puede haber un campo de respaldo "privado" para las listas que también llena el deserializador.
Entonces mi pregunta es: ¿existe una forma (preferiblemente simple) de evitar duplicar artículos en el siguiente caso?
Código
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace JsonSerializeExample
{
public class Program
{
static void Main()
{
var data = new SomeData();
var json = JsonConvert.SerializeObject(data);
Console.WriteLine("First : {0}", json);
var data2 = JsonConvert.DeserializeObject<SomeData>(json);
var json2 = JsonConvert.SerializeObject(data2);
Console.WriteLine("Second: {0}", json2);
}
}
public class SomeData
{
public string SimpleField;
public int[] IntArray;
public IList<int> IntListProperty { get; set; }
public IList<int> IntListMember;
public SomeData()
{
SimpleField = "Some data";
IntArray = new[] { 7, 8, 9 };
IntListProperty = new List<int> { 1, 2, 3 };
IntListMember = new List<int> { 4, 5, 6 };
}
}
}
Resultado resultante
First : {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6],"IntListProperty":[1,2,3]}
Second: {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6,4,5,6],"IntListProperty":[1,2,3,1,2,3]}
Puede haber cierta superposición aquí con Json.Net duplica elementos de la lista privada . Sin embargo, creo que mi problema es aún más simple, y todavía no lo he descubierto.
Eso es porque está agregando elementos en el constructor. Un enfoque común en deserializadores al procesar una lista es básicamente:
- lea la lista a través del getter
- si la lista es nula: cree una nueva lista y asigne a través del conjunto de propiedades, si
- deserializar cada elemento a su vez, y anexar (
Add
) a la lista
esto es porque la mayoría de los miembros de la lista no tienen setters , es decir,
public List<Foo> Items {get {...}} // <=== no set
Contraste con las matrices, que deben tener un colocador para ser útil; de ahí que el enfoque sea usualmente:
- deserializar cada elemento por turno y anexar (
Add
) a una lista temporal - convertir la lista en una matriz (
ToArray
) y asignarla a través del setter
Algunos serializadores le dan opciones para controlar este comportamiento (otros no); y algunos serializadores le dan la capacidad de eludir completamente al constructor (otros no).