jsonconvert deserializeobject deserialize c# asp.net-web-api json.net json-deserialization

c# - deserializeobject - JSON.NET: ¿Cómo deserializar la propiedad de la interfaz basada en el valor del objeto principal(titular)?



deserialize json to object c# (1)

Tengo tales clases

class Holder { public int ObjType { get; set; } public List<Base> Objects { get; set; } } abstract class Base { // ... doesn''t matter } class DerivedType1 : Base { // ... doesn''t matter } class DerivedType2 : Base { // ... doesn''t matter }

Usando WebAPI, quiero recibir el objeto Holder y deserializarlo correctamente. Basado en el valor de ObjType , necesito que la propiedad Objects se deserialice como List<DerivedType1> ( ObjType == 1 ) o List<DerivedType2> ( ObjType == 2 ).

En este momento busqué SO e Internet para obtener el mejor enfoque, pero lo mejor que he encontrado es esta respuesta https://stackoverflow.com/a/8031283/1038496 . El problema de esta solución es que pierde el contexto del objeto principal, por lo que no puedo averiguar el valor de ObjType . OK, podría resolverlo creando un JsonConverter personalizado para Holder y recordando el valor de ObjType , pero aun así tengo miedo de esta línea

serializer.Populate(jObject.CreateReader(), target);

como el comentario debajo de esta respuesta dice

El nuevo JsonReader creado en el método ReadJson no hereda ninguno de los valores de configuración del lector original (Culture, DateParseHandling, DateTimeZoneHandling, FloatParseHandling, etc ...). Estos valores deben copiarse antes de usar el nuevo JsonReader en serializer.Populate ().

lo cual es un problema para mí y copiar estos valores por mi cuenta no me parece limpio (¿y si me pierdo algo?)

Entonces, la pregunta es: ¿hay un mejor enfoque que me he perdido para deserializar la propiedad del objeto abstracto en función del valor de la propiedad principal?


Estás en el camino correcto. Necesita implementar un JsonConverter personalizado para su clase de Holder para manejar esta situación, como sugirió. Pero no se preocupe, es posible escribir el convertidor de manera que pueda usar las instancias originales de lector y serializador que se transfieren al convertidor, sin tener que copiar las configuraciones a instancias nuevas. Así es como lo escribiría:

class HolderConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(Holder)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jo = JObject.Load(reader); Holder holder = new Holder(); holder.ObjType = (int)jo["ObjType"]; holder.Objects = new List<Base>(); foreach (JObject obj in jo["Objects"]) { if (holder.ObjType == 1) holder.Objects.Add(obj.ToObject<DerivedType1>(serializer)); else holder.Objects.Add(obj.ToObject<DerivedType2>(serializer)); } return holder; } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }

Aquí hay una demostración rápida:

class Program { static void Main(string[] args) { string json = @" [ { ""ObjType"" : 1, ""Objects"" : [ { ""Id"" : 1, ""Foo"" : ""One"" }, { ""Id"" : 2, ""Foo"" : ""Two"" }, ] }, { ""ObjType"" : 2, ""Objects"" : [ { ""Id"" : 3, ""Bar"" : ""Three"" }, { ""Id"" : 4, ""Bar"" : ""Four"" }, ] }, ]"; List<Holder> list = JsonConvert.DeserializeObject<List<Holder>>(json); foreach (Holder holder in list) { if (holder.ObjType == 1) { foreach (DerivedType1 obj in holder.Objects) { Console.WriteLine("Id: " + obj.Id + " Foo: " + obj.Foo); } } else { foreach (DerivedType2 obj in holder.Objects) { Console.WriteLine("Id: " + obj.Id + " Bar: " + obj.Bar); } } } } } [JsonConverter(typeof(HolderConverter))] class Holder { public int ObjType { get; set; } public List<Base> Objects { get; set; } } abstract class Base { public int Id { get; set; } } class DerivedType1 : Base { public string Foo { get; set; } } class DerivedType2 : Base { public string Bar { get; set; } }

Salida:

Id: 1 Foo: One Id: 2 Foo: Two Id: 3 Bar: Three Id: 4 Bar: Four