2011-09-27 7 views
11

Tengo una clase de colección que implementa IEnumerable y estoy teniendo problemas para deserializar una versión serializada de la misma. Estoy usando Json.net v 4.0.2.13623serialización Json.net de colección personalizada implementando IEnumerable <T>

Aquí es una versión más simple de mi clase de colección que ilustra mi problema

public class MyType 
{ 
    public int Number { get; private set; } 
    public MyType(int number) 
    { 
    this.Number = number; 
    } 
} 

public class MyTypes : IEnumerable<MyType> 
{ 
    private readonly Dictionary<int, MyType> c_index; 
    public MyTypes(IEnumerable<MyType> seed) 
    { 
    this.c_index = seed.ToDictionary(item => item.Number); 
    } 
    public IEnumerator<MyType> GetEnumerator() 
    { 
    return this.c_index.Values.GetEnumerator(); 
    } 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
    return this.GetEnumerator(); 
    } 
    public int CustomMethod() 
    { 
    return 1; // Just for illustration 
    } 
} 

Cuando serializarlo me sale el siguiente JSON

[ 
    { 
    "Number": 1 
    }, 
    { 
    "Number": 2 
    } 
] 

Pero cuando trato de deserializar recibo la siguiente excepción System.Exception: No se puede crear y poblar la lista tipo MyTypes

Have also t Ried uso de sugerencias de serialización, pero no han tenido éxito

Estos son la función de prueba que he utilizado

public void RoundTrip() 
{ 
    var _myTypes1 = new MyTypes(new[] { new MyType(1), new MyType(2) }); 
    var _jsonContent = JsonConvert.SerializeObject(_myTypes1, Formatting.Indented); 
    var _myTypes2 = JsonConvert.DeserializeObject<MyTypes>(_jsonContent); 
} 
public void RoundTripWithSettings() 
{ 
    var _myTypes1 = new MyTypes(new[] { new MyType(1), new MyType(2) }); 

    var _serializationSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Arrays }; 
    var _jsonContent = JsonConvert.SerializeObject(_myTypes1, Formatting.Indented, _serializationSettings); 
    var _myTypes2 = JsonConvert.DeserializeObject<MyTypes>(_jsonContent, _serializationSettings); 
} 

nadie ha logrado serializar sus propios objetos de colección?

Gracias de antemano

Pat

+4

Debe serializar y deserializar colecciones concretas como la Lista en lugar de IEnumerable . Para deserializar algo, necesita una implementación en lugar de solo una interfaz. – Deleted

+0

Chris, alterado a la subclase ReadOnlyCollection con algunos otros cambios, pero puedo saber deserializar la colección – pmcgrath

+1

En realidad, también se puede usar un IList . Creará una Lista para usted. Pero no hay una colección predeterminada definida para IEnumerable . – Mithon

Respuesta

2

creo JSON .NET depende de tener un constructor sin parámetros para los tipos que Deserializa a. Desde el punto de vista de la deserialización, no tiene idea de qué proporcionarle al contratista.

cuanto a su colección, de nuevo ¿Cómo se supone que saber cómo rellenar una implementación de IEnumerable<T> que sólo define cómo enumerar la colección no cómo rellenar la misma. En su lugar, debe deserializar directamente a algún estándar IEnumerable<MyType> (o directamente al IEnumerable<MyType> que creo que admite JSON.NET) y luego pasarlo a su constructor.

Creo que todo lo siguiente debería funcionar en este caso:

var _myTypes2 = new MyTypes(JsonConvert.DeserializeObject<MyTypes[]>(_jsonContent)); 
var _myTypes2 = new MyTypes(JsonConvert.DeserializeObject<List<MyTypes>>(_jsonContent)); 
var _myTypes2 = new MyTypes(JsonConvert.DeserializeObject<IEnumerable<MyTypes>>(_jsonContent)); 

Como alternativa, aunque más trabajo, si es necesario deserializado directamente se puede implementar algo así como IList en su colección que debería permitir JSON.NET para utilizar los métodos IList para poblar su colección.

+0

Desde esta respuesta, la biblioteca ha ampliado sus capacidades: funcionará con un constructor sin parámetros (como siempre lo ha hecho) pero también admitirá la creación de una instancia que tome todos sus datos a través de un constructor y admitirá tipos de colecciones que tengan un constructor que toma un IEnumerable (como la respuesta por @dbc menciona). –

2

A partir de Json.NET 6.0 versión 3 y posterior (Probé en 8.0.3), esto funciona automáticamente siempre que la clase personalizada que implementa IEnumerable<MyType> tenga un constructor que tome un argumento de entrada IEnumerable<MyType>. Desde el release notes:

Para todos los futuros creadores de colecciones .NET inmutables: Si su colección de T tiene un constructor que toma IEnumerable continuación Json.NET funcionará automáticamente cuando deserializar a su colección, de lo contrario eres todo lo alto De suerte.

Puesto que la clase MyTypes en la pregunta tiene solo un constructor tal, esto ahora simplemente funciona. Violín de demostración: https://dotnetfiddle.net/LRJHbd.

En ausencia de un constructor de este tipo, habría que añadir un constructor sin parámetros y ejecutar ICollection<MyType> (en lugar de sólo IEnumerable<MyType>) con un Add(MyType item) método de trabajo. Json.NET puede construir y poblar la colección. O deserializar a una colección intermedia como en el original answer.

Cuestiones relacionadas