使用动态数量的对象和键反序列化 json

问题描述 投票:0回答:1

我有一个需要反序列化的 json 字符串(在 WPF 应用程序中,使用 System.Net.Json)。树中的子对象(节点)包含可变数量的具有变量名称的属性/节点。 “最小”样本如下所示:

“间隔”:[{ “时间戳”:1677477728, “123456”:{ “子区间”:[{ “最大值”:“56.7”, “标签”:“Leq” }, { “最大”:“58.1”, “标签”:“Lmax” } ] } }, { “时间戳”:1677477730, “54321”:{ “子区间”:[{ “价值”:“58.5”, “标签”:“Leq” }, { “价值”:“59.5”, “标签”:“Lmax” } ] }, “56789”:{ “子区间”:[{ “价值”:“78.2”, “标签”:“Lmax” }, { “价值”:“74.3”, “标签”:“Leq” } ] } } ]

即一个带有“时间戳”的数组“间隔”和以数字字符串作为键的不同数量的对象/节点。

随着以下

public class IntervalMeta
    {
        public long? Timestamp { get; set; }
        [JsonExtensionData]
        public Dictionary<string, JsonElement>? MeasurementPoints { get; set; } = new();
    }

这给出了一个包含 JsonElements 的字典,我可以逐步查看它并查找所需的属性。如果有一个

就好了
public Dictionary<string, SubInterval>? MeasurementPoints { get; set; } = new();

在哪里

SubInterval

public class SubInterval
    {
        public string? Max { get; set; }
        public string? Label { get; set; }
    }

我希望并尝试制作一个我可以使用的自定义 JsonConverter,但有许多我不知道如何处理的问题: 问题 0:如何让它使用自定义 JsonConverter?

我对转换器的尝试:

public class MeasurementPointDictionaryJsonConverter : JsonConverter<Dictionary<string, SubInterval>>
    {
        public override Dictionary<string, SubInterval>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var dict = new Dictionary<string, SubInterval>();
            // Issue 3: How do loop over the contents in the Interval node (containing 0 or more SubIntervals)
            while (reader.Read())
            {
                // Issue 1: How do I read the key?
                var measurementPointId = reader.GetString();
                // Issue 2: How do I deserialize the node to a SubInterval?
                string value = reader.GetString();
                var interval = JsonSerializer.Deserialize<SubInterval>(value, options);
                
                dict.Add(measurementPointId ?? "", interval ?? new());
            }
            return dict;
        }

        public override void Write(Utf8JsonWriter writer, Dictionary<string, SubInterval> value, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
    }

我试过用以下方法装饰

MeasurementPoints

[JsonConverter(typeof(MeasurementPointDictionaryJsonConverter))]
public Dictionary<string, SubInterval>? MeasurementPoints { get; set; } = new();

但这只会导致

MeasurementPoints == null
。添加
JsonExtensionData
属性:

[JsonExtensionData]
[JsonConverter(typeof(MeasurementPointDictionaryJsonConverter))]
public Dictionary<string, SubInterval>? MeasurementPoints { get; set; } = new();

尝试反序列化时抛出错误(似乎

JsonExtensionData
只能处理Dictionary或Dictionary)。

任何帮助将不胜感激(我问过 chatgtp 但我没有给我更多 :))。

c# json dynamic system.text.json jsonconverter
1个回答
0
投票

我想出了这样的东西。

但在此之前,我想指出,在您的字典中,您没有单数 SubInterval,而是 SubInterval 的集合。如果我错了,请纠正我。

转换器:

 public class CustomConverter : JsonConverter<List<IntervalMeta>>
 {
        public override List<IntervalMeta> Read(ref Utf8JsonReader reader, Type typeToConvert,
            JsonSerializerOptions options)
        {
            using var jsonDocument = JsonDocument.ParseValue(ref reader);
            var root = jsonDocument.RootElement;

            var intervals = root.GetProperty("intervals").EnumerateArray();

            var values = new List<IntervalMeta>();

            foreach (var interval in intervals)
            {
                var item = new IntervalMeta();

                foreach (var property in interval.EnumerateObject())
                {
                    if (property.Name == "timestamp")
                    {
                        if (property.Value.TryGetInt64(out var value))
                        {
                            item.Timestamp = value;
                        }

                        continue;
                    }

                    Dictionary<string, SubInterval[]> subIntervalDict =
                        JsonSerializer.Deserialize<Dictionary<string, SubInterval[]>>(
                            property.Value.GetRawText(), options);
                    item.MeasurementPoints = subIntervalDict;
                }

                values.Add(item);
            }

            return values;
        }

        public override void Write(Utf8JsonWriter writer, List<IntervalMeta> value, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
  }

我用于测试的其余代码:

public class IntervalMeta
{
    public long? Timestamp { get; set; }

    public Dictionary<string, SubInterval[]> MeasurementPoints { get; set; } = new();
}

public class SubInterval
{
    public string Max { get; set; }
    public string Label { get; set; }
}

class Program
{
    static async Task Main(string[] args)
    {
        var input = @"
        {
           ""intervals"":[
              {
                 ""timestamp"":1677477728,
                 ""123456"":{
                    ""subintervals"":[
                       {
                          ""max"":""56.7"",
                          ""label"":""Leq""
                       },
                       {
                          ""max"":""58.1"",
                          ""label"":""Lmax""
                       }
                    ]
                 }
              },
              {
                 ""timestamp"":1677477730,
                 ""54321"":{
                    ""subintervals"":[
                       {
                          ""value"":""58.5"",
                          ""label"":""Leq""
                       },
                       {
                          ""value"":""59.5"",
                          ""label"":""Lmax""
                       }
                    ]
                 },
                 ""56789"":{
                    ""subintervals"":[
                       {
                          ""value"":""78.2"",
                          ""label"":""Lmax""
                       },
                       {
                          ""value"":""74.3"",
                          ""label"":""Leq""
                       }
                    ]
                 }
              }
           ]
        }";

        var test = JsonSerializer.Deserialize<List<IntervalMeta>>(input, new JsonSerializerOptions
        {
            Converters = { new CustomConverter() },
            PropertyNameCaseInsensitive = true
        });

        Console.WriteLine(test);
    }
© www.soinside.com 2019 - 2024. All rights reserved.