C # JSON.NET – Deserializar la respuesta que utiliza una estructura de datos inusual

Tengo algunos problemas para encontrar una forma limpia (como sea posible) de deserializar algunos datos JSON en un formato particular. Quiero deserializar los datos a clases de objetos de datos fuertemente tipados, bastante flexible con respecto a los detalles de esto. Aquí hay un ejemplo de cómo se ven los datos:

{ "timestamp": 1473730993, "total_players": 945, "max_score": 8961474, "players": { "Player1Username": [ 121, "somestring", 679900, 5, 4497, "anotherString", "thirdString", "fourthString", 123, 22, "YetAnotherString"], "Player2Username": [ 886, "stillAstring", 1677, 1, 9876, "alwaysAstring", "thirdString", "fourthString", 876, 77, "string"] } } 

Las partes específicas de las que no estoy seguro son:

  1. ¿La colección de jugadores se consideraría un diccionario? El nombre de usuario podría servir como la clave, pero el valor me está arrojando, ya que sería una colección mixta de valores enteros y de cadena.
  2. Un jugador se compone completamente de valores sin nombre. Casi siempre he trabajado con datos JSON que tenían propiedades y valores nombrados (por ejemplo, timestamp, total_players, etc. en la parte superior)

Digamos que tengo una clase de nivel superior como esta:

 public class ScoreboardResults { public int timestamp { get; set; } public int total_players { get; set; } public int max_score { get; set; } public List players { get; set; } } 

¿Cómo se vería el objeto Player dado que básicamente es una clave / valor con el nombre de usuario que sirve como clave, y el valor es una colección de enteros y cadenas mixtos? Los datos para cada elemento jugador siempre están en el mismo orden, así que sé que el primer valor en la colección es su UniqueID, el segundo valor es la descripción del jugador, etc. Me gustaría que la clase de jugador fuera algo como esto:

 public class Player { public string Username { get; set; } public int UniqueID { get; set; } public string PlayerDescription { get; set; } .... .... .... Following this pattern for all of the values in each player element .... .... } 

Estoy seguro de que esto es bastante sencillo de hacer con JSON.NET, y es por eso que quería evitar cualquiera de las ideas que tenía sobre cómo lograr esto. Lo que se me ocurrió fue poco elegante y, probablemente, propenso a errores durante el proceso de serialización.

EDITAR

Estas son las clases que se generan al usar el pasado como clases JSON como lo sugiere snow_FFFFFF :

 public class Rootobject { public int timestamp { get; set; } public int total_players { get; set; } public int max_score { get; set; } public Players players { get; set; } } public class Players { public object[] Player1Username { get; set; } public object[] Player2Username { get; set; } } 

Lo que no tengo claro es cómo deserializar los datos JSON en el elemento “jugadores” como una lista con Player1Username como una propiedad de cadena simple en el objeto Player. En cuanto a la recostackción de cadenas y enteros entremezclados, estoy seguro de que puedo obtenerlos en propiedades individuales en el objeto Player sin problemas.

El convertidor de Deserializing JSON en Visual Basic .NET debe hacer lo que necesita, traducido adecuadamente de VB.NET a c #:

 public class ObjectToArrayConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(T) == objectType; } static bool ShouldSkip(JsonProperty property) { return property.Ignored || !property.Readable || !property.Writable; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var type = value.GetType(); var contract = serializer.ContractResolver.ResolveContract(type) as JsonObjectContract; if (contract == null) throw new JsonSerializationException("invalid type " + type.FullName); var list = contract.Properties.Where(p => !ShouldSkip(p)).Select(p => p.ValueProvider.GetValue(value)); serializer.Serialize(writer, list); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; var token = JArray.Load(reader); var contract = serializer.ContractResolver.ResolveContract(objectType) as JsonObjectContract; if (contract == null) throw new JsonSerializationException("invalid type " + objectType.FullName); var value = existingValue ?? contract.DefaultCreator(); foreach (var pair in contract.Properties.Where(p => !ShouldSkip(p)).Zip(token, (p, v) => new { Value = v, Property = p })) { var propertyValue = pair.Value.ToObject(pair.Property.PropertyType, serializer); pair.Property.ValueProvider.SetValue(value, propertyValue); } return value; } } 

A continuación, agregue el convertidor a su clase de Player e indique el orden de cada propiedad usando JsonPropertyAttribute.Order :

 [JsonConverter(typeof(ObjectToArrayConverter))] public class Player { [JsonProperty(Order = 1)] public int UniqueID { get; set; } [JsonProperty(Order = 2)] public string PlayerDescription { get; set; } // Other fields as required. } 

Entonces, finalmente, declara tu objeto raíz de la siguiente manera:

 public class ScoreboardResults { public int timestamp { get; set; } public int total_players { get; set; } public int max_score { get; set; } public Dictionary players { get; set; } } 

Tenga en cuenta que he movido el nombre de Username fuera de la clase Player y en el diccionario, como una clave.

Una buena forma de comenzar sería dejar que visual studio genere su clase basada en el JSON. Abra un archivo de clase en blanco y vaya a EDITAR -> PEGAR ESPECIAL -> PASTE JSON como CLASES.

Esto generará un archivo con la (s) clase (s) necesaria (s) para serializar / deserializar su JSON.

Prueba esto

Crea una clase como abajo

Nota: puede usar la opción Pegar especial en Visual Studio para generar todas las clases relacionadas con el JSON

Editar -> Pegar especial -> Pegar Json como clases

creará todas las clases relacionadas con el JSON

Nota: remita esto ya he respondido de esta manera ..