[英]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() { }
}
替代方案:
如果您在Canteen
類JToken
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。
然后,您可以從食堂數組訪問每個食堂,並檢索每個食堂的name
, src
和food
鍵/值對。
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.