C# 当JSON字典为空时,反序列化JSON字符串失败

C# 当JSON字典为空时,反序列化JSON字符串失败,c#,json.net,C#,Json.net,当前,当我尝试使用Newtonsoft.json对从第三方收到的json字符串进行反序列化时,我面临以下问题(->我无法自己更改收到的json字符串): json包含一个字典(以及一些我在这里没有列出的其他条目): 我创建了一个类,其中包含属性(加上此处未列出的属性): 在这种情况下,食物似乎不是字典而是数组。 这就是愿望化失败并出现以下错误的原因: Newtonsoft.Json.JsonSerializationException:“无法反序列化 将当前JSON数组(例如[1,2,3])转换

当前,当我尝试使用Newtonsoft.json对从第三方收到的json字符串进行反序列化时,我面临以下问题(->我无法自己更改收到的json字符串):

json包含一个字典(以及一些我在这里没有列出的其他条目):

我创建了一个类,其中包含属性(加上此处未列出的属性):

在这种情况下,食物似乎不是字典而是数组。 这就是愿望化失败并出现以下错误的原因:

Newtonsoft.Json.JsonSerializationException:“无法反序列化 将当前JSON数组(例如[1,2,3])转换为类型 'System.Collections.Generic.Dictionary'2[System.String,System.String]' 因为该类型需要一个JSON对象(例如{“name”:“value”})来 正确反序列化。若要修复此错误,请将JSON更改为 JSON对象(例如{“name”:“value”})或将反序列化类型更改为 实现集合接口的数组或类型(例如。 可以从JSON反序列化的类似ICollection(IList)的列表 还可以将array.JsonArrayAttribute添加到类型中以强制其 从JSON数组反序列化。路径“food”。”

有人能帮我解决这个问题吗

编辑 理想化代码:

public T DeserializeAPIResults<T>(string json)
{
        JObject obj = JsonConvert.DeserializeObject<JObject>(json);
        return obj.GetValue("canteen").ToObject<T>();
}
不带值的完整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() { }
}
公共密封类食堂
{
[JsonProperty(“名称”)]
公共字符串名称{get;set;}
[JsonProperty(“src”)]
公共字符串Src{get;set;}
[JsonProperty(“食品”)]
公共字典食物{get;set;}
公共食堂(){}
}
和方法调用:

Canteen[] canteens = DeserializeAPIResults<Canteen[]>(json);
食堂[]食堂=反序列化APIResults(json);
如果特定键的值不是固定的,并且数据必须是可配置的,那么Newtonsoft.json有一个功能可以在这里使用,那就是
[JsonExtensionData]

扩展数据现在在序列化对象时写入。通过读取和写入扩展数据,可以自动往返所有JSON,而无需将每个属性添加到要反序列化的.NET类型中。只声明您感兴趣的属性,其余的由扩展数据完成

当您的第三方json有一个名为
food
且其值为object的键时,您试图反序列化到
Dictionary food{get;set;}
,并且您的反序列化方法正确地反序列化了您的json

但是当
food
key have array时,您的方法无法反序列化,因为您试图将数组
[]
反序列化为
字符串

如果你使用

[JsonExtensionData]
public Dictionary<string, JToken> Food { get; set; }
然后,无论
food
键是object还是array,都可以成功地反序列化json

然后,您可以从食堂数组访问您的每个食堂,并检索每个食堂的
名称
src
食品
键/值对等

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 "[]"
    }
}
食堂[]食堂=反序列化APIResults(json); foreach(食堂中的var食堂) { 字符串名称=食堂名称; 字符串src=食堂.src; JToken food=食堂食品; if(food.Type==JTokenType.Object) { 字典食品=食品。ToObject(); } else if(food.Type==JTokenType.Array) { //如果“foods”是空数组“[]”,请执行某些操作 } }
表示您的
食物
键包含有时对象和有时数组,对吗?看起来像。当食物不是空的时候,它总是一本字典。只有当它为空时才会被视为数组。显示反序列化代码吗?我已添加了反序列化code@er-他说当食物是空的,它会像空数组一样返回,但当它不是空的时候,它会返回字典。非常感谢!我刚刚尝试了你的解决方案,它对我很有效。我以前没有见过[JsonExtensionData]特性。我唯一要问自己的是为什么第三方会这样做。如果没有数据,他们为什么不能返回一个空白字典而不是数组呢?很高兴听到这个消息,我也有同样的问题。无论如何欢迎你:)我还添加了
[JsonExtensionData]
的替代方案。请查看答案中的备选部分:)感谢您对此问题的第二个解决方案。我想我会使用它,因为它似乎对我的方法更有用。不管怎样,第一版也不错:)
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);
[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() { }
}
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() { }
}
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 "[]"
    }
}