如何用C#的System.Text.Json反序列化子数组数量可变的JSON数组
问题描述
我需要将图表JSON数据反序列化为List<List<double>>,但该JSON的chart字段存在两种格式:
- 单个点时为单数组:
{"data" : { "chart": [ 1, 1 ] } }
- 多个点时为数组的数组:
{"data": {"chart": [ [ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ]]}}
目前我可通过以下类反序列到List<object>:
public class Data { public List<object> chart { get; set; } } public class Root { public Data data { get; set; } }
但希望统一得到List<List<double>>。请问:
- 能否通过System.Text.Json的自定义转换器实现?具体怎么做?
- 能否对chart1、chart2等多个图表字段实现该逻辑?
注:无法修改JSON生成方的代码。
解决方案
1. 用System.Text.Json自定义转换器实现
可以实现,具体步骤如下:
步骤1:编写自定义JsonConverter
创建继承自JsonConverter<List<List<double>>>的转换器,在Read方法中处理两种格式:
using System.Text.Json; using System.Text.Json.Serialization; public class ChartDataConverter : JsonConverter<List<List<double>>> { public override List<List<double>> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartArray) { // 先尝试反序列化为嵌套数组 try { return JsonSerializer.Deserialize<List<List<double>>>(ref reader, options); } catch { // 失败则重置读取器,按单层数组处理 reader = new Utf8JsonReader(reader.CurrentSpan); var singlePoint = JsonSerializer.Deserialize<List<double>>(ref reader, options); return new List<List<double>> { singlePoint }; } } throw new JsonException("Invalid chart data format"); } public override void Write(Utf8JsonWriter writer, List<List<double>> value, JsonSerializerOptions options) { // 序列化时统一输出嵌套数组格式 JsonSerializer.Serialize(writer, value, options); } }
步骤2:在模型中应用转换器
修改Data类,将chart字段类型改为List<List<double>>并添加转换器特性:
public class Data { [JsonConverter(typeof(ChartDataConverter))] public List<List<double>> chart { get; set; } } public class Root { public Data data { get; set; } }
步骤3:反序列测试
使用常规反序列化代码即可完成转换:
var json1 = @"{""data"" : { ""chart"": [ 1, 1 ] } }"; var result1 = JsonSerializer.Deserialize<Root>(json1); // result1.data.chart 为包含一个元素 [1,1] 的 List<List<double>> var json2 = @"{""data"": {""chart"": [ [ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ]]}}"; var result2 = JsonSerializer.Deserialize<Root>(json2); // result2.data.chart 为包含四个元素的 List<List<double>>
2. 对多个图表字段复用逻辑
完全可以,有两种实现方式:
方式1:给每个字段单独添加特性
直接在Data类的多个图表字段上应用同一个转换器特性:
public class Data { [JsonConverter(typeof(ChartDataConverter))] public List<List<double>> chart { get; set; } [JsonConverter(typeof(ChartDataConverter))] public List<List<double>> chart1 { get; set; } [JsonConverter(typeof(ChartDataConverter))] public List<List<double>> chart2 { get; set; } }
方式2:全局注册转换器
如果所有List<List<double>>类型的字段都需要该逻辑,可将转换器注册到JsonSerializerOptions中,无需逐个添加特性:
var options = new JsonSerializerOptions(); options.Converters.Add(new ChartDataConverter()); // 反序列化时传入该配置 var result = JsonSerializer.Deserialize<Root>(json, options);
这种方式下,所有模型中类型为List<List<double>>的字段都会自动应用该转换器,适合大量同类型字段的场景。
内容的提问来源于stack exchange,提问作者GI1
相关产品推荐
相关产品推荐

