簡體   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