簡體   English   中英

JSON字典為空時,反序列化JSON字符串失敗

[英]Deserializing JSON string fails when JSON dictionary is empty

當前,當我嘗試使用Newtonsoft.Json反序列化從第三方收到的json字符串(->我自己不能更改接收到的json字符串)時, 遇到以下問題

json包含一個字典(以及一些我在這里未列出的條目):

"food": {
        "Menu 1": "abc",
        "Menu 2": "def"
}

我創建了一個包含該屬性的類(以及我在此處未列出的屬性):

Dictionary<string, string> Food {get; set;}

在這種情況下,對json的反序列化工作正常。 食物為空時會發生此問題:

{
      "food": [],
}

在這種情況下,food似乎不是字典而是數組。 這就是為什么反序列化失敗並顯示以下錯誤的原因:

Newtonsoft.Json.JsonSerializationException:“無法將當前JSON數組(例如[1,2,3])反序列化為類型'System.Collections.Generic.Dictionary`2 [System.String,System.String]',因為該類型需要一個要正確反序列化的JSON對象(例如{“ name”:“ value”})。要解決此錯誤,請將JSON更改為JSON對象(例如{“ name”:“ value”})或將反序列化類型更改為數組或實現了可從JSON數組反序列化的List等集合接口(例如ICollection,IList)的類型。還可以將JsonArrayAttribute添加到該類型中,以強制從JSON數組反序列化。路徑為“食物”。

請問有人可以幫助我解決這個問題嗎?

編輯反序列化代碼:

public T DeserializeAPIResults<T>(string json)
{
        JObject obj = JsonConvert.DeserializeObject<JObject>(json);
        return obj.GetValue("canteen").ToObject<T>();
}

編輯2具有值的完整json:

        {
        "canteen": [
            {
                "name": "Canteen1",
                "src": "a link",
                "food": {
                    "Menu 1": "abc",
                    "Menu 2": "def",
                    "Menu 3": "ghi",
                    "Menu 4": "jkl",
                    "Menu 5": "mno"
                }
            },
            {
                "name": "Canteen2",
                "src": "a link",
                "food": {
                    "Menu 1": "abc",
                    "Menu 2": "def",
                    "Menu 3": "ghi"
                }
            },
            {
                "name": "Canteen3",
                "src": "a link",
                "food": {
                    "Line 1": "abc",
                    "Line 2": "def",
                    "Line 3": "ghi"
                }
            }
        ]
    }

不含值的完整json:

{
    "canteen": [
        {
            "name": "Canteen1",
            "src": "a link",
            "food": [],
        },
        {
            "name": "Canteen2",
            "src": "a link",
            "food": [],
        },
        {
            "name": "Canteen3",
            "src": "a link",
            "food": [],
       }
    ]
}

編輯3該類:

public sealed class Canteen
{
    [JsonProperty("name")]
    public string Name { get; set; }
    [JsonProperty("src")]
    public string Src { get; set; }
    [JsonProperty("food")]
    public Dictionary<string, string> Food { get; set; }
    public Canteen() { }
}

和方法調用:

Canteen[] canteens = DeserializeAPIResults<Canteen[]>(json);

如果您特定鍵的值不是固定的並且數據必須可配置,則Newtonsoft.json具有要在此處使用的一項功能,即[JsonExtensionData] 閱讀更多

現在,當對象被序列化時,擴展數據將被寫入。 讀取和寫入擴展數據可以自動往返所有JSON,而無需將所有屬性添加到要反序列化的.NET類型。 只聲明您感興趣的屬性,讓擴展數據完成其余的工作。

當您的第三方json具有名稱為food且其值為對象的鍵時,您正嘗試反序列化為Dictionary<string, string> Food {get; set;} Dictionary<string, string> Food {get; set;}並且您的反序列化方法可以正確地反序列化json。

但是,當food鍵具有array時,您的方法將無法反序列化,因為您正嘗試將array []反序列化為string

如果您使用

[JsonExtensionData]
public Dictionary<string, JToken> Food { get; set; }

代替

Dictionary<string, string> Food {get; set;}

然后您的反序列化工作。

所以最后你的課將是

public sealed class Canteen
{
    [JsonProperty("name")]
    public string Name { get; set; }
    [JsonProperty("src")]
    public string Src { get; set; }

    [JsonExtensionData]
    public Dictionary<string, JToken> Food { get; set; }
    public Canteen() { }
}

替代方案:

如果您在CanteenJToken Food屬性數據類型聲明為JToken ,例如

public sealed class Canteen
{
    [JsonProperty("name")]
    public string Name { get; set; }
    [JsonProperty("src")]
    public string Src { get; set; }

    [JsonProperty("food")]
    public JToken Food { get; set; }

    public Canteen() { }
}

然后,無論您的food密鑰是對象還是數組,您都可以成功反序列化json。

然后,您可以從食堂數組訪問每個食堂,並檢索每個食堂的namesrcfood鍵/值對。

JToken的優點是您可以檢查其類型是對象還是數組

Canteen[] canteens = DeserializeAPIResults<Canteen[]>(json);

foreach (var canteen in canteens)
{
    string name = canteen.Name;
    string src = canteen.Src;
    JToken food = canteen.Food;

    if (food.Type == JTokenType.Object)
    {
        Dictionary<string, string> foods = food.ToObject<Dictionary<string, string>>();
    }
    else if (food.Type == JTokenType.Array)
    {
        //Do something if "foods" is empty array "[]"
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM