[英]How do I deserialize an array of objects with varying names?
In a Windows Phone app using C#, I am trying to deserialize some JSON with the following structure: 在使用C#的Windows Phone应用中,我尝试使用以下结构反序列化一些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"
} }
]
This is a list of toys in which the names of the toys (kite, puzzle, ball) are not known in advance. 这是玩具列表,其中的玩具(风筝,拼图,球)的名称事先未知。 I don't have any control over the format of the JSON.
我对JSON的格式没有任何控制。
Using json2csharp.com I get the following classes: 使用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; }
}
This looks to me like an array of "toy" objects but I don't know what approach to take when deserializing this. 在我看来,这看起来像“玩具”对象的数组,但是我不知道在反序列化时采取什么方法。
The only code that I have had work is the basic: 我曾经工作过的唯一代码是基本代码:
var root = JsonConvert.DeserializeObject(rawJSON);
I thought something like the following might work, but I would lose the name of the toy if it worked (and it doesn't): 我认为类似以下内容的方法可能会起作用,但如果该玩具有效(并且无效),我会丢失该玩具的名称:
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>));
Any suggestions please? 有什么建议吗?
You are close. 你近了 If you define your
Toy
class as you have it in your question, you can deserialize into a List<Dictionary<string, Toy>>
. 如果在问题中定义自己的
Toy
类,则可以反序列化为List<Dictionary<string, Toy>>
。 Thus, each toy is actually represented by a Dictionary
with a single entry in it. 因此,每个玩具实际上是由一个
Dictionary
表示的,其中只有一个条目。 The Key
is the name of the toy and the Value
is the Toy
info. Key
是玩具的名称, Value
是Toy
信息。
Here is a demo: 这是一个演示:
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();
}
This outputs the following: 输出以下内容:
toy: kite
supplier: ABC
cost: 7.98 (GBP)
toy: puzzle
supplier: DEF
cost: 7.98 (USD)
toy: ball
supplier: DEF
cost: 5.49 (USD)
Admittedly, this solution is kind of "clunky", because it would be better to have the name of the toy included in the Toy
class itself rather than have an intervening Dictionary
to stumble over. 诚然,此解决方案有点“笨拙”,因为最好将玩具的名称包含在
Toy
类本身中,而不是插在中间的Dictionary
更好。 There are two ways to fix this. 有两种方法可以解决此问题。 One way is to add a
Name
property on the Toy
class, deserialize into the same structure as shown above, then do a little bit of post-processing to move the names from each Dictionary
into the respective Toy
, building a new List<Toy>
in the process. 一种方法是在
Toy
类上添加Name
属性,反序列化为与上面所示的结构相同,然后进行一些后期处理,以将名称从每个Dictionary
移动到相应的Toy
,从而构建一个新的List<Toy>
正在进行中。 The second way to do it is to create a custom JsonConverter
to handle this translation during deserialization. 第二种方法是创建一个自定义
JsonConverter
以在反序列化期间处理此转换。 I'd be happy to demonstrate either of these alternate approaches if you wish. 如果您愿意,我很乐于演示这些替代方法中的任何一种。 Just let me know.
请让我知道。 If you just need quick-and-dirty, then the above approach should do.
如果您只需要快捷的方法,那么上面的方法应该可以解决。
Alternative approach using a custom JsonConverter 使用自定义JsonConverter的替代方法
This approach is a little "cleaner" because we can keep all the Toy
info together on a single strongly-typed object, and keep all the deserialization logic separate so it doesn't clutter up the main code. 这种方法有点“清洁”,因为我们可以将所有
Toy
信息都放在一个强类型的对象上,并且将所有反序列化逻辑分开,以免使主代码混乱。
First, we need to alter your Toy
class to give it a Name
property. 首先,我们需要更改您的
Toy
类以为其提供Name
属性。
class Toy
{
public string Name { get; set; }
public string Supplier { get; set; }
public string Currency { get; set; }
public decimal Cost { get; set; }
}
Next, we create a class which inherits from JsonConverter
. 接下来,我们创建一个继承自
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();
}
}
To use the converter, we just need to create an instance of it and pass it in the call to DeserializeObject<T>()
. 要使用转换器,我们只需要创建一个实例并将其传递给
DeserializeObject<T>()
的调用即可。 Now that we have this converter, we can deserialize directly into a List<Toy>
, which is much more natural. 现在有了转换器,我们可以直接反序列化为
List<Toy>
,这自然得多。
List<Toy> toys = JsonConvert.DeserializeObject<List<Toy>>(json, new ToyConverter());
Accessing the toy data from there is straightforward. 从那里访问玩具数据很简单。
foreach (Toy toy in toys)
{
Console.WriteLine("toy: " + toy.Name);
Console.WriteLine("supplier: " + toy.Supplier);
Console.WriteLine("cost: " + toy.Cost + " (" + toy.Currency + ")");
Console.WriteLine();
}
You'll notice this gives exactly the same output as the previous example, but the code is much cleaner. 您会注意到,它给出的输出与上一个示例完全相同,但是代码更加简洁。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.