如何反序列化对象的具有不同名称的数组?(How do I deserialize an array

2019-10-18 18:38发布

在使用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"
      } }
]

这是其中的玩具(风筝,益智,球)的名称预先不知道玩具的名单。 我没有在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>));

有什么建议吗?

Answer 1:

你靠近。 如果你定义你的Toy类,你在你的问题有它,你可以反序列化到一个List<Dictionary<string, Toy>> 。 因此,每个玩具实际上是由a表示Dictionary在它的一个条目。 该Key是玩具的名称和ValueToy的信息。
这里是一个演示:

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

你会发现这给准确的输出与前面的例子相同,但代码干净多了。



文章来源: How do I deserialize an array of objects with varying names?