【问题标题】:Deserialize json array with both fields and dictionary反序列化包含字段和字典的 json 数组
【发布时间】:2019-07-24 14:22:50
【问题描述】:

我想创建一个 C# 类来使用 Newtonsoft.Json 反序列化这个 JSON:

[
    {
        "awb": "2205900120010",
        "oras destinatar": "",
        "continut": "",
        "nume confirmare": "",
        "data confirmare": "",
        "ora confirmare": "",
        "awb retur": "",
        "0": {
            "id": 0,
            "status": "AWB-ul nu a fost predat catre FAN Courier",
            "data": "",
            "ora": "",
            "oras": "",
            "traseu": ""
        }
    },
    {
        "awb": "5345899260009",
        "oras destinatar": "Tamaseu",
        "continut": "COMANDA 16201",
        "nume confirmare": "Szilagyi Ileana",
        "data confirmare": "13.12.2018",
        "ora confirmare": "17:16",
        "awb retur": "",
        "0": {
            "id": 1,
            "status": "Expeditie in livrare",
            "data": "12.12.2018",
            "ora": "14:46",
            "oras": "Lugoj",
            "traseu": "Expeditia a fost preluata de catre FAN Courier in data 12.12.2018 14:46."
        },
        "1": {
            "id": 1,
            "status": "Expeditie in livrare",
            "data": "12.12.2018",
            "ora": "19:35",
            "oras": "Lugoj",
            "traseu": "Expeditia a plecat din hub-ul FAN Courier Lugoj spre hub-ul de destinatie in data 12.12.2018 19:35."
        },
        "2": {
            "id": 2,
            "status": "Livrat",
            "data": "13.12.2018",
            "ora": "10:46",
            "oras": "Oradea",
            "traseu": "Expeditia a fost preluata spre livrare de catre curierul din orasul Oradea in data 13.12.2018 10:46."
        },
        "3": {
            "id": 2,
            "status": "Livrat",
            "data": "13.12.2018",
            "ora": "17:16",
            "oras": "Oradea",
            "traseu": "Ultimul status al expeditiei: livrat in data 13.12.2018 17:16."
        }
    }
]

已经尝试反序列化

var list = JsonConvert.DeserializeObject<List<AwbTrackingResponse>>(text);

Events 仍然为空。

public class AwbTrackingResponse
{
    [JsonProperty("awb")]
    public string Awb { get; set; }
    [JsonProperty("oras destinatar")]
    public string DestinationCity { get; set; }
    [JsonProperty("continut")]
    public string Content { get; set; }
    [JsonProperty("nume confirmare")]
    public string ConfirmedName { get; set; }
    [JsonProperty("data confirmare")]
    public string ConfirmedDate { get; set; }
    [JsonProperty("ora confirmare")]
    public string ConfirmedHour { get; set; }
    [JsonProperty("awb retur")]
    public string AwbReturn { get; set; }
    // ???
    public Dictionary<int, AwbTrackingEvent> Events { get; set; }
}

public class AwbTrackingEvent
{
    [JsonProperty("id")]
    public int Id { get; set; }
    [JsonProperty("status")]
    public string Status { get; set; }
    [JsonProperty("data")]
    public string Date { get; set; }
    [JsonProperty("ora")]
    public string Time { get; set; }
    [JsonProperty("oras")]
    public string City { get; set; }
    [JsonProperty("traseu")]
    public string Route { get; set; }
}

我预计Events 字典也会被填充,但现在它仍然为空。我不确定 Newtonsoft.Json 库是否支持这种类型的反序列化。如果是,那么也许我可以提示我的 C# 类需要更改的内容,如果不是,那么也许我将获得另一种方法来将此 JSON 数据转换为可从 C# 代码中使用。

【问题讨论】:

  • 我不确定是否有一种简单或干净的方法可以做到这一点。您可以将 AwbTrackingResponse 替换为 Dictionary&lt;string, object&gt; 并手动处理属性。或者您更有可能需要一个自定义转换器。

标签: c# json json.net deserialization


【解决方案1】:

Json.Net 有一个“Extension Data”功能可以应对这种情况。如果您使用 [JsonExtensionData] 属性标记字典,则该字典将使用 JSON 中未在类中定义属性的键值对填充。问题是,字典必须声明为Dictionary&lt;string, object&gt;Dictionary&lt;string, JToken&gt;。既然你想要Dictionary&lt;int, AwbTrackingEvent&gt;,我建议这个想法:

  1. 在您的类中定义一个 Dictionary&lt;string, JToken&gt; 类型的私有 EventData 属性,以从 JSON 中捕获额外数据,并使用 [JsonExtensionData] 属性对其进行标记。
  2. 更改公共Events 属性以将EventData 字典与Dictionary&lt;int, AwbTrackingEvent&gt; 相互转换。用[JsonIgnore]标记此属性。
  3. 然后,像往常一样反序列化,它应该可以按您的意愿工作。

这是它在代码中的样子:

public class AwbTrackingResponse
{
    ...

    [JsonExtensionData]
    private Dictionary<string, JToken> EventData { get; set; }

    [JsonIgnore]
    public Dictionary<int, AwbTrackingEvent> Events
    {
        get
        {
            return EventData?.ToDictionary(
                kvp => Convert.ToInt32(kvp.Key), 
                kvp => kvp.Value.ToObject<AwbTrackingEvent>()
            );
        }
        set
        {
            EventData = value?.ToDictionary(
                kvp => kvp.Key.ToString(),
                kvp => JToken.FromObject(kvp.Value)
            );
        }
    }
}

这是一个工作演示:https://dotnetfiddle.net/Dz9HY0

【讨论】:

  • 是的,这解决了问题。我今天早上刚测试过,效果很好。我很高兴 Json.Net 足够灵活来处理这种 json 数据。谢谢布赖恩
【解决方案2】:

你的 Json 字符串有一些问题。 首先在你的关键元素中有空格,例如

"data confirmare": "",

这应该是:

"data_confirmare": "",

使用 json2sharp.com 和 jsonlint.com 来整理。 到目前为止,我有以下内容可以帮助您:

[{
    "awb": "2205900120010",
    "events": [{
        "0": {
            "id": 0,
            "status": "AWB-ul nu a fost predat catre FAN Courier"
        }
    }]

},
{
    "awb": "5345899260009",
    "oras_destinatar": "Tamaseu",
    "continut": "COMANDA 16201",
    "nume_confirmare": "Szilagyi Ileana",
    "data_confirmare": "13.12.2018",
    "ora_confirmare": "17:16",
    "awb_retur": "",
    "events": [{
            "0": {
                "id": 1,
                "status": "Expeditie in livrare",
                "data": "12.12.2018",
                "ora": "14:46",
                "oras": "Lugoj",
                "traseu": "Expeditia a fost preluata de catre FAN Courier in data 12.12.2018 14:46."
            }
        },
        {
            "1": {
                "id": 1,
                "status": "Expeditie in livrare",
                "data": "12.12.2018",
                "ora": "19:35",
                "oras": "Lugoj",
                "traseu": "Expeditia a plecat din hub-ul FAN Courier Lugoj spre hub-ul de destinatie in data 12.12.2018 19:35."
            }
        },
        {
            "2": {
                "id": 2,
                "status": "Livrat",
                "data": "13.12.2018",
                "ora": "10:46",
                "oras": "Oradea",
                "traseu": "Expeditia a fost preluata spre livrare de catre curierul din orasul Oradea in data 13.12.2018 10:46."
            }
        },
        {
            "3": {
                "id": 2,
                "status": "Livrat",
                "data": "13.12.2018",
                "ora": "17:16",
                "oras": "Oradea",
                "traseu": "Ultimul status al expeditiei: livrat in data 13.12.2018 17:16."
            }
        }
    ]
}

]

【讨论】:

  • 不幸的是,我无法控制 json 数据的生成方式。我只需要从我的 C# 代码中使用它,所以我一直在努力寻找一个优雅的反序列化解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多