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

标签 c# json.net

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

json 包含一个字典(以及我未在此处列出的其他一些条目):

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

我创建了一个包含属性的类(以及我没有在此处列出的属性):
Dictionary<string, string> Food {get; set;}

在这种情况下,json 的反序列化工作正常。
当食物为空时出现问题:
{
      "food": [],
}

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

Newtonsoft.Json.JsonSerializationException: "Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,System.String]' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array. Path 'food'."



请问有大佬能帮我解决一下这个问题吗?

编辑
反序列化代码:
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] . Read more

Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.



当您的第 3 方 json 具有名称为 food 的 key 时及其作为对象的值,然后您尝试反序列化为 Dictionary<string, string> Food {get; set;}并且您的反序列化方法正确反序列化您的 json。

但是当 food键有数组,则您的方法无法反序列化,因为您正在尝试反序列化数组 []进入 string .

如果你使用
[JsonExtensionData]
public Dictionary<string, JToken> Food { get; set; }

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

然后你的反序列化工作。

所以最后你的类(class)将是
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() { }
}

替代:

如果您声明您的 Food属性数据类型为 JToken在您的 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() { }
}

然后你就可以成功反序列化你的 json 无论你的 food键是对象或数组。

然后你可以从 canteens 数组访问你的每个 canteen 并检索每个 canteen 的 name , srcfood键/值对之类的。

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 "[]"
    }
}

关于c# - 当 JSON 字典为空时,反序列化 JSON 字符串失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53458399/

相关文章:

c# - 无法安装 Newtonsoft Json

c# - Json.NET 基本类型 - 使用 Decimal 而不是 Double

c# - 将 UDP 数据包转发到多个保持原始源地址的 IP

C# 线程任务 - 无法从任务数组中获取返回值

c# - 使用 JSON.Net 序列化数据的问题

c# - Json.NET:如何从生成的 json 字符串中的类型中删除程序集信息?

c# - 使用 Newtonsoft.Json,getter 中属性的支持字段是什么

c# - 匹配运算符

c# - 你调用的对象是空的。 - App.config

c# - 无法在窗口上设置自定义位置