2013-10-10 4 views
1

В телефоне приложении Windows, с помощью C#, я пытаюсь десериализация некоторых JSON со следующей структурой:Как десериализовать массив объектов с разными именами?

[ { "kite" : { "supplier" : "ABC", 
     "currency" : "GBP", 
     "cost" : "7.98" 
     } }, 
    { "puzzle" : { "supplier" : "DEF", 
     "currency" : "USD", 
     "cost" : "7.98" 
     } }, 
    { "ball" : { "supplier" : "DEF", 
     "currency" : "USD", 
     "cost" : "5.49" 
     } } 
] 

Это список игрушек, в которых имена игрушек (змей, головоломка, шар) являются не известно заранее. Я не контролирую формат JSON.

Использование json2csharp.com я получаю следующие классы:

public class Kite 
{ 
    public string supplier { get; set; } 
    public string currency { get; set; } 
    public string cost { get; set; } 
} 

public class Puzzle 
... 

public class Ball 
... 

public class RootObject 
{ 
    public Kite kite { get; set; } 
    public Puzzle puzzle { get; set; } 
    public Ball ball { get; set; } 
} 

Это смотрит на меня как массив «игрушечных» объектов, но я не знаю, какой подход принять при десериализации это.

Единственный код, который я имел работу является основным:

var root = JsonConvert.DeserializeObject(rawJSON); 

Я думал, что-то вроде следующего может работать, но я потерял бы название игрушке, если она работала (и это не):

public class Toy 
{ 
    public string supplier { get; set; } 
    public string currency { get; set; } 
    public string cost { get; set; } 
} 
List<Toy> toyList = (List<Toy>) JsonConvert.DeserializeObject(rawJSON, typeof(List<Toy>)); 

Любые предложения, пожалуйста?

+0

Похоже, что это был бы словарь. Кайт, головоломка и мяч будут ключами. Значения были бы типом, если бы объект имел свойства поставщика, валюты и стоимости. Однако я не могу исследовать, как десериализовать это на данный момент. Однако я хотел бы изучить какой-то динамический объект и, возможно, перевести его в нечто более конкретное. –

ответ

1

Вы близко. Если вы определяете свой класс Toy, как у вас есть в своем вопросе, вы можете deserialize в List<Dictionary<string, Toy>>. Таким образом, каждая игрушка фактически представлена ​​Dictionary с одной записью в ней. Key - название игрушки, а Value - это информация Toy.
Вот демо:

string json = @" 
[ { ""kite"" : { ""supplier"" : ""ABC"", 
     ""currency"" : ""GBP"", 
     ""cost"" : ""7.98"" 
     } }, 
    { ""puzzle"" : { ""supplier"" : ""DEF"", 
     ""currency"" : ""USD"", 
     ""cost"" : ""7.98"" 
     } }, 
    { ""ball"" : { ""supplier"" : ""DEF"", 
     ""currency"" : ""USD"", 
     ""cost"" : ""5.49"" 
     } } 
]"; 

List<Dictionary<string, Toy>> list = 
     JsonConvert.DeserializeObject<List<Dictionary<string, Toy>>>(json); 

foreach (Dictionary<string, Toy> dict in list) 
{ 
    KeyValuePair<string, Toy> kvp = dict.First(); 
    Console.WriteLine("toy: " + kvp.Key); 
    Console.WriteLine("supplier: " + kvp.Value.Supplier); 
    Console.WriteLine("cost: " + kvp.Value.Cost + " (" + kvp.Value.Currency + ")"); 
    Console.WriteLine(); 
} 

Это выводит следующее:

toy: kite 
supplier: ABC 
cost: 7.98 (GBP) 

toy: puzzle 
supplier: DEF 
cost: 7.98 (USD) 

toy: ball 
supplier: DEF 
cost: 5.49 (USD) 

Следует признать, что это решение является своего рода «неуклюжим», потому что было бы лучше иметь название игрушки включены в самом классе Toy, а не вмешиваться Dictionary, чтобы споткнуться. Есть два способа исправить это. Один из способов - добавить свойство Name в класс Toy, десериализовать в ту же структуру, что и показано выше, затем сделать небольшую постобработку, чтобы переместить имена из каждого Dictionary в соответствующие Toy, построив новый List<Toy> в процессе , Второй способ сделать это - создать пользовательский JsonConverter для обработки этого перевода во время десериализации. Я бы с удовольствием продемонстрировал любой из этих альтернативных подходов, если вы пожелаете. Просто дай мне знать. Если вам просто нужно быстро и грязно, тогда должен действовать вышеуказанный подход.

Альтернативный подход с использованием пользовательских JsonConverter

Этот подход немного «чище», потому что мы можем держать всю информацию Toy вместе на одном строго типизированный объект и сохранить все логики десериализации отдельно, так что не загромождает основной код.

Прежде всего, мы должны изменить ваш класс Toy, чтобы дать ему Name.

class Toy 
{ 
    public string Name { get; set; } 
    public string Supplier { get; set; } 
    public string Currency { get; set; } 
    public decimal Cost { get; set; } 
} 

Далее мы создаем класс, который наследуется от JsonConverter.

class ToyConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     // This lets JSON.Net know that this converter can handle Toy objects 
     return (objectType == typeof(Toy)); 
    } 

    public override object ReadJson(JsonReader reader, 
     Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     // load the toy JSON object into a JObject 
     JObject jo = JObject.Load(reader); 

     // get the first (and only) property of the object 
     JProperty prop = jo.Properties().First(); 

     // deserialize the value of that property (which is another 
     // object containing supplier and cost info) into a Toy instance 
     Toy toy = prop.Value.ToObject<Toy>(); 

     // get the name of the property and add it to the newly minted toy 
     toy.Name = prop.Name; 

     return toy; 
    } 

    public override void WriteJson(JsonWriter writer, 
     object value, JsonSerializer serializer) 
    { 
     // If you need to serialize Toys back into JSON, then you'll need 
     // to implement this method. We can skip it for now. 
     throw new NotImplementedException(); 
    } 
} 

Чтобы использовать конвертер, нам просто нужно создать экземпляр этого и передать его в вызове DeserializeObject<T>(). Теперь, когда у нас есть этот конвертер, мы можем десериализовать непосредственно в List<Toy>, что намного более естественно.

List<Toy> toys = JsonConvert.DeserializeObject<List<Toy>>(json, new ToyConverter()); 

Доступ к данным о игрушках осуществляется прямолинейно.

foreach (Toy toy in toys) 
{ 
    Console.WriteLine("toy: " + toy.Name); 
    Console.WriteLine("supplier: " + toy.Supplier); 
    Console.WriteLine("cost: " + toy.Cost + " (" + toy.Currency + ")"); 
    Console.WriteLine(); 
} 

Вы заметите, что это дает точно такой же результат, как в предыдущем примере, но код намного чище.

+0

Брайан, я не получу изменения, чтобы протестировать ваше предложение выше, но позже он выглядит великолепно! Мне было бы очень интересно узнать, как вы будете использовать пользовательский JsonConverter, потому что это не то, что я знаю. – John

+0

Несомненно. Я обновил свой ответ с помощью этого альтернативного подхода. –

Смежные вопросы