简体   繁体   English

如何对具有不同名称的对象数组进行反序列化?

[英]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是玩具的名称, ValueToy信息。
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.

相关问题 如何将XML反序列化为Point对象数组 - How do I deserialize this XML back into an array of Point objects 如何使用非标准(和不同的)属性名称反序列化JSON(在.NET中) - How do deserialize JSON with non-standard (and varying) property names (in .NET) 如何反序列化没有名称的JSON.NET对象? - How do I deserialize JSON.NET objects that don't have names? 如何将对象树反序列化为DTO? - How do I deserialize a tree of objects into a DTO? C# 如何正确地将数组中的多个自定义对象反序列化为一个对象? - C# How do I correctly deserialize multiple custom objects in an array to an object? 如何将JSON对象数组反序列化为C#匿名类型? - How do I deserialize an array of JSON objects to a C# anonymous type? 如何使用 Newtonsoft 在 C# 中反序列化包含对象的 JSON 数组 - How do I deserialize a JSON Array containing objects, in C# with Newtonsoft 如何反序列化具有基于日期的属性名称的 Json? - How do I deserialize Json that has date based property names? 如何将xml反序列化为一个对象数组? - How to Deserialize xml to an array of objects? 如何反序列化具有不同类型和元素数量的元素的JSON数组? - How to deserialize a JSON array of elements with different types and varying number of elements?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM