newtonsoft - serializar json c#
¿Qué deserializador Json representa colecciones IList<T>? (3)
Estoy tratando de deserializar json a un modelo de objetos donde las colecciones se representan como tipos IList<T>
.
La deserialización real está aquí:
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Deserialize<IList<Contact>>(
(new StreamReader(General.GetEmbeddedFile("Contacts.json")).ReadToEnd()));
Antes de publicar la excepción que recibo, debes saber cuáles son las conversiones implícitas. Este es el tipo de Contact
:
public class Contact
{
public int ID { get; set; }
public string Name { get; set; }
public LazyList<ContactDetail> Details { get; set; }
//public List<ContactDetail> Details { get; set; }
}
Y este es el tipo ContactDetail
:
public class ContactDetail
{
public int ID { get; set; }
public int OrderIndex { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
Lo importante de saber con LazyList<T>
es que implementa IList<T>
:
public class LazyList<T> : IList<T>
{
private IQueryable<T> _query = null;
private IList<T> _inner = null;
private int? _iqueryableCountCache = null;
public LazyList()
{
this._inner = new List<T>();
}
public LazyList(IList<T> inner)
{
this._inner = inner;
}
public LazyList(IQueryable<T> query)
{
if (query == null)
throw new ArgumentNullException();
this._query = query;
}
Ahora esta definición de la clase LazyList<T>
estaba bien hasta que intenté deserializar a Json en ella. El System.Web.Script.Serialization.JavaScriptSerializer
parece querer serializar listas a List<T>
cual tiene sentido por su edad, pero las necesito en el tipo IList<T>
para que se LazyList<T>
en mi LazyList<T>
( al menos ahí es donde creo que me estoy equivocando).
Obtengo esta excepción:
System.ArgumentException: Object of type ''System.Collections.Generic.List`1[ContactDetail]'' cannot be converted to type ''LazyList`1[ContactDetail]''..
Cuando intento usar List<ContactDetail>
en mi tipo de Contact
(como puede ver en el comentario anterior) parece funcionar. Pero no quiero usar List<T>
. Incluso traté de que mi LazyList<T>
heredara de List<T>
que parecía ejecutarse, pero pasar la T[]
interna de List<T>
a mi implementación fue una pesadilla y simplemente no quiero la hinchazón de List<T>
en cualquier parte de mi modelo.
También probé con otras bibliotecas json en vano (es posible que no las utilice al máximo. Reemplacé más o menos las referencias e intenté repetir el código citado en la parte superior de esta pregunta. ¿¿ayuda??).
No sé qué probar ahora. ¿Me voy con otro deserializador? ¿Ajusto la deserialización? ¿Debo cambiar mis tipos para complacer al deserializador? ¿Debo preocuparme más por el casting implícito o simplemente implementar otra interfaz?
Desafortunadamente, es probable que necesites arreglar tu clase, ya que no hay forma de que un deserializador sepa que debe ser de tipo IList, ya que List es una implementación de IList.
Como los deserializadores en http://json.org tienen una fuente disponible, puede modificar una para hacer lo que quiera.
No es posible deserializar directamente a una interfaz, ya que las interfaces son simplemente un contrato. JavaScriptSerializer tiene que deserializarse a algún tipo concreto que implemente IList <T>, y la opción más lógica es List <T>. Tendrá que convertir la lista en una LazyList, que dado el código que publicó, debería ser lo suficientemente fácil:
var list = serializer.Deserialize<IList<Contact>>(...);
var lazyList = new LazyList(list);
Terminé usando la lib de Json.NET, que tiene una buena compatibilidad con linq para la asignación personalizada. Esto es a lo que mi deserialización terminó pareciéndose:
JArray json = JArray.Parse(
(new StreamReader(General.GetEmbeddedFile("Contacts.json")).ReadToEnd()));
IList<Contact> tempContacts = (from c in json
select new Contact
{
ID = (int)c["ID"],
Name = (string)c["Name"],
Details = new LazyList<ContactDetail>(
(
from cd in c["Details"]
select new ContactDetail
{
ID = (int)cd["ID"],
OrderIndex = (int)cd["OrderIndex"],
Name = (string)cd["Name"],
Value = (string)cd["Value"]
}
).AsQueryable()),
Updated = (DateTime)c["Updated"]
}).ToList<Contact>();
return tempContacts;