繁体   English   中英

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

[英]How do I deserialize an array of objects with varying names?

在使用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>));

有什么建议吗?

你近了 如果在问题中定义自己的Toy类,则可以反序列化为List<Dictionary<string, Toy>> 因此,每个玩具实际上是由一个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更好。 有两种方法可以解决此问题。 一种方法是在Toy类上添加Name属性,反序列化为与上面所示的结构相同,然后进行一些后期处理,以将名称从每个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();
}

您会注意到,它给出的输出与上一个示例完全相同,但是代码更加简洁。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM