【问题标题】:How to deserialize JSON with dynamic and static key names in C#如何在 C# 中使用动态和静态键名反序列化 JSON
【发布时间】:2020-03-16 03:09:00
【问题描述】:

我必须反序列化来自具有以下结构的 api 的响应:

[
  {
    "starttime": "...",
    "endtime": "....",
    "var1": {},
    "var2": {}
  },
  {
    "starttime": "...",
    "endtime": "....",
    "var1": {},
    "var3": {}
  },
  {
    "starttime": "...",
    "endtime": "....",
    "var1": {}
  }
] 

一些见解:

  • JSON 是一个对象数组
  • 数组中的每个对象都将始终具有“starttime”和“endtime”属性
  • 对象“var1”、“var2”、“var3”在它们内部总是具有相同的属性...但问题是对象键(var1、var2 或 var3)是动态的。它可以是任何字符串,而且这种对象的数量是动态的(我可以有 3 个或零个“var”对象)。

我在想这样的事情,将 JSON 字符串反序列化为具有属性“starttime”、“endtime”的对象列表和包含所有“var”对象的字典。

public class MyResponse
{
    [JsonProperty(PropertyName = "starttime")]
    public string StartTime { get; set; }
    [JsonProperty(PropertyName = "endtime")]
    public string EndTime { get; set; }
    public Dictionary<string, VarObject> VarData { get; set; }
}

但 VarData 属性始终为空。

有人试过这样的吗?

【问题讨论】:

  • 您可以将整个 JSON 反序列化为 List&lt;Dictionary&lt;string, object&gt;&gt;
  • @DavidG 是的,这会起作用,但是我需要访问所有属性(甚至是开始时间和结束时间,我知道它们将永远存在)作为字典的键......这确实似乎不是最干净的解决方案。
  • 它可能不是特别干净,但你的 JSON 在这方面也不是特别干净。
  • @HimBromBeere 所以你说要制作我自己的转换器?在您发送的示例中,在 ReadJson 方法中,这个人已经知道他的属性将被命名为“type”。我的问题是我不知道名字,它可能是“var1”,也可能是“pepe”

标签: c# serialization json.net deserialization


【解决方案1】:

你有两种选择,第一种是直接反序列化为List&lt;Dictionary&lt;string, object&gt;&gt;,例如:

var responses = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(json);

或者,如果您坚持使用您的对象,您将需要编写一个自定义转换器。例如,像这样:

public class MyResponseConverter : JsonConverter
{
    public override bool CanConvert(Type type) => type == typeof(MyResponse);

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var responseObject = JObject.Load(reader);

        MyResponse response = new MyResponse
        {
            StartTime = (string)responseObject["starttime"],
            EndTime = (string)responseObject["endtime"],
        };

        var varData = new Dictionary<string, object>();

        foreach (var property in responseObject.Properties())
        {
            if(property.Name == "starttime" || property.Name == "endtime")
            {
                continue;
            }

            varData.Add(property.Name, property.Value);
        }

        response.VarData = varData;
        return response;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // If you want to write to JSON, you will need to implement this method
        throw new NotImplementedException();
    }
}

你的班级会稍微改成这样:

[JsonConverter(typeof(MyResponseConverter))]
public class MyResponse
{
    [JsonProperty(PropertyName = "starttime")]
    public string StartTime { get; set; }
    [JsonProperty(PropertyName = "endtime")]
    public string EndTime { get; set; }

    public Dictionary<string, object> VarData { get; set; }
}

现在你像这样反序列化:

var responses = JsonConvert.DeserializeObject<List<MyResponse>>(json);

【讨论】:

  • 感谢@DavidG,我实现了与此非常相似的东西,它就像一个魅力
【解决方案2】:

您可以在这里查看示例https://dotnetfiddle.net/QgXWQi

但是为了更灵活,这个逻辑最好在标记为[OnDeserialized]的方法中实现

喜欢这里https://www.newtonsoft.com/json/help/html/SerializationAttributes.htm

主要思路是将其解析为JObject,然后转换为Dictionary

    var jObj = JObject.Parse(jsonText);
    var varData = jObj
        .Children<JProperty>()
        .Where(p => p.Name  != "starttime" && p.Name  != "endtime")
        .ToDictionary(x=> x.Name, x => ((JObject)x.Value).ToObject<VarObject>());

【讨论】:

    猜你喜欢
    • 2021-01-13
    • 2012-11-11
    • 2021-04-19
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    相关资源
    最近更新 更多