C # JSON.NET – Deserialize a resposta que usa uma estrutura de dados incomum

Estou tendo alguns problemas para descobrir uma maneira limpa (possível) de desserializar alguns dados JSON em um formato específico. Eu quero desserializar os dados para classs de object de dados fortemente tipados, bastante flexíveis em relação às especificidades disso. Aqui está um exemplo de como os dados se parecem:

{ "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"] } } 

As partes específicas sobre as quais não tenho certeza são:

  1. A coleção de jogadores seria considerada um dictionary? O nome de usuário poderia servir como chave, mas o valor está me descartando, já que seria uma coleção mista de valores de string e inteiro.
  2. Um jogador é composto inteiramente por valores sem nome. Eu sempre trabalhei com dados JSON que tinham propriedades e valores nomeados (ex. Timestamp, total_players, etc. no topo)

Digamos que eu tenha uma class de nível 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; } } 

Como seria o object Player, uma vez que é basicamente uma chave / valor com o nome de usuário servindo como chave e o valor sendo uma coleção de inteiros e cadeias de caracteres mistos? Os dados para cada elemento de jogador estão sempre na mesma ordem, então eu sei que o primeiro valor na coleção é seu UniqueID, o segundo valor é uma descrição de jogador, etc. Eu gostaria que a class de jogador fosse algo assim:

 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 .... .... } 

Tenho certeza de que essa é uma coisa bem simples de se fazer usando o JSON.NET, e é por isso que eu queria evitar qualquer uma das ideias que tive sobre como fazer isso. O que eu criei teria sido deselegante e provavelmente propenso a erros em algum grau durante o processo de serialização.

EDITAR

Aqui estão as classs que são geradas ao usar o passado como classs JSON conforme sugerido por 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; } } 

O que não está claro para mim é como eu desserializo os dados JSON no elemento “players” como uma List with Player1Username sendo uma propriedade de string simples no object Player. Quanto à coleção de strings e números inteiros misturados, estou confiante de que posso obtê-los em propriedades individuais no object Player sem problema.

O conversor de Deserializing JSON no Visual Basic .NET deve fazer o que você precisa, traduzido adequadamente do VB.NET para 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; } } 

Em seguida, adicione o conversor à sua class Player e indique a ordem de cada propriedade 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. } 

Então, finalmente, declare seu object raiz da seguinte forma:

 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; } } 

Note que eu mudei o Username da class Player para o dictionary, como uma chave.

Uma boa maneira de começar seria deixar o visual studio gerar sua class com base no JSON. Abra um arquivo de class em branco e vá para EDITAR -> COLAR ESPECIAL -> COLAR JSON COMO CLASSES.

Isso gerará um arquivo com as classs necessárias para serializar / desserializar seu JSON.

Tente isso

Crie uma aula como abaixo

Nota: você pode usar a opção Colar Especial no visual studio para gerar todas as classs relacionadas ao JSON

Editar -> Colar Especial -> Colar Json como Classes

ele criará todas as classs relacionadas ao JSON

Nota: referir isso eu já respondo semelhante assim ..