2011-08-17 9 views
25

Tengo un problema con la deserialización JSON que involucra una matriz de objetos polimórficos. He intentado las soluciones para la serialización documentadas here y here que funcionan muy bien para la serialización, pero ambas explotan en la deserialización.Deserialización JSON con una matriz de objetos polimórficos

Mi estructura de clases es el siguiente:

IDable

[DataContract(IsReference=true)] 
public abstract class IDable<T> { 

    [DataMember] 
    public T ID { get; set; } 
} 

Grupo de Observación

[DataContract(IsReference=true)] 
[KnownType(typeof(DescriptiveObservation))] 
[KnownType(typeof(NoteObservation))] 
[KnownType(typeof(NumericObservation))] 
[KnownType(typeof(ScoredObservation))] 
public class ObservationGroup : IDable<int> { 

    [DataMember] 
    public string Title { get; set; } 

    [DataMember] 
    public List<Observation> Observations { get; set; } 

    [OnDeserializing] 
    void OnDeserializing(StreamingContext context) 
    { 
     init(); 
    } 

    public ObservationGroup() { 
     init(); 
    } 

    private void init() 
    { 
     Observations = new List<Observation>(); 
     ObservationRecords = new List<ObservationRecord>(); 
    } 

} 

DescriptiveObservation

[DataContract(IsReference = true)] 
public class DescriptiveObservation : Observation 
{ 

    protected override ObservationType GetObservationType() 
    { 
     return ObservationType.Descriptive; 
    } 
} 

NoteObservation

[DataContract(IsReference = true)] 
public class NoteObservation : Observation 
{ 
    protected override ObservationType GetObservationType() 
    { 
     return ObservationType.Note; 
    } 
} 

NumericObservation

[DataContract(IsReference = true)] 
public class NumericObservation : Observation 
{ 
    [DataMember] 
    public double ConstraintMaximum { get; set; } 
    [DataMember] 
    public double ConstraintMinimum { get; set; } 
    [DataMember] 
    public int PrecisionMaximum { get; set; } 
    [DataMember] 
    public int PrecisionMinimum { get; set; } 
    [DataMember] 
    public string UnitType { get; set; } 

    protected override ObservationType GetObservationType() 
    { 
     return ObservationType.Numeric; 
    } 
} 

ScoredObservation

[DataContract(IsReference = true)] 
public class ScoredObservation : Observation { 
    [DataMember] 
    public int Value { get; set; } 

    protected override ObservationType GetObservationType() { 
     return ObservationType.Scored; 
    } 
} 

soy imparcial para usar ya sea el construido en JavaScriptSerializer o la biblioteca Newtonsoft JSON.

código de serialización

var settings = new Newtonsoft.Json.JsonSerializerSettings(); 
settings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects; 

Newtonsoft.Json.JsonConvert.SerializeObject(AnInitializedScoresheet, Newtonsoft.Json.Formatting.None, settings); 

Código Deserialización

return Newtonsoft.Json.JsonConvert.DeserializeObject(returnedStringFromClient, typeof(Scoresheet)); 
//Scoresheet contains a list of observationgroups 

El error que consigo es

"No se pudo crear una instancia del tipo ProjectXCommon.DataStores.Observation. El tipo es una interfaz o clase abstracta y no puede ser instantada ".

¡Cualquier ayuda sería muy apreciada!

+0

Estoy bastante seguro de que está relacionado con su '' Lista los deserializadores están tratando de crear una instancia de un tipo de 'Observation' no el tipo específico que realmente es Con Newtonsoft puede anular partes de la deserialización agregando su propio convertidor (aquí hay un ejemplo https://gist.github.com/1140171). No estoy seguro de cuánto le ayudará esto, aunque no estoy del todo seguro pero bastante cierto este es el caso. :) – Buildstarted

+0

json muestras serían útiles – Frank

Respuesta

28

No ha agregado ninguna configuración después de la deserialización. Debe aplicar la configuración con TypeNameHandling establecida en Object o All.

De esta manera:

JsonConvert.DeserializeObject(
    returnedStringFromClient, 
    typeof(Scoresheet), 
    new JsonSerializerSettings 
    { 
     TypeNameHandling = TypeNameHandling.Objects 
    }); 

Documentación: TypeNameHandling setting

+0

Doh! Para aquellos que todavía usan .NET JavascriptSerializer, también pueden usar 'nuevo JavaScriptSerializer (nuevo System.Web.Script.Serialization.SimpleTypeResolver()). Deserialize (returnedStringFromClient, typeof (Scoresheet));' – Chainlink

+1

A partir de RavenDB build 499 (RavenDB usa JSON.NET) al usar una Lista genérica donde T es una interfaz, debe agregar el atributo [JsonProperty (TypeNameHandling = TypeNameHandling.All)]. Esto corrige la excepción "No se pudo crear una instancia del tipo 'su interfaz' El tipo es una interfaz o clase abstracta y no se puede instalar". – DalSoft

Cuestiones relacionadas