JsonSerializer反序列化:源属性全为数组但目标非数组如何处理
适配全数组包装JSON的反序列化方案
问题说明
输入JSON的所有属性值都被包装为数组格式,无论目标属性实际是单值还是数组类型,示例JSON:
{ "StringValue": ["mystringvalue"], "StringArrayValue": ["value1","value2"], "LongValue": [123] }
目标接收类定义:
class MyClass { public string StringValue {get;set;} public string[] StringArrayValue {get;set;} public long LongValue {get;set;} }
默认System.Text.Json反序列化会抛出类型不匹配异常,因为无法直接将JSON数组转换为非数组的CLR类型,需要自定义转换逻辑实现:目标属性为非数组类型时,自动读取对应JSON数组的第一个元素赋值;目标属性为数组类型时,正常读取全部数组元素完成反序列化。
实现步骤
1. 编写通用转换器
实现JsonConverterFactory做全局类型适配,不需要为每个属性单独打特性,所有非数组类型自动走取数组首元素的逻辑:
using System.Text.Json; using System.Text.Json.Serialization; public class ArrayWrappedValueConverter : JsonConverterFactory { public override bool CanConvert(Type typeToConvert) { // 数组类型走默认反序列化逻辑,不拦截 return !typeToConvert.IsArray; } public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { var innerConverterType = typeof(InnerArrayConverter<>).MakeGenericType(typeToConvert); return (JsonConverter)Activator.CreateInstance(innerConverterType)!; } private class InnerArrayConverter<T> : JsonConverter<T> { public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException($"当前值不是数组格式,无法转换为{typeof(T).Name}类型"); reader.Read(); // 取数组第一个元素反序列化为目标类型 var result = JsonSerializer.Deserialize<T>(ref reader, options); // 跳过数组内剩余元素直到数组结束 while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; reader.Skip(); } return result!; } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { // 序列化时默认包装为数组,和输入格式对齐 writer.WriteStartArray(); JsonSerializer.Serialize(writer, value, options); writer.WriteEndArray(); } } }
如果仅需要处理反序列化场景,不需要序列化输出和输入格式保持一致,可直接将Write方法实现改为抛出NotSupportedException,或者直接写入单值不做数组包装。
2. 配置反序列化选项
将转换器加入JsonSerializerOptions,反序列化时传入即可:
var jsonOptions = new JsonSerializerOptions { Converters = { new ArrayWrappedValueConverter() }, PropertyNameCaseInsensitive = true // 按需开启属性名大小写不敏感匹配 }; // 执行反序列化 MyClass instance = JsonSerializer.Deserialize<MyClass>(jsonContent, jsonOptions);
效果验证
反序列化后得到的实例:
StringValue赋值为数组首元素"mystringvalue"StringArrayValue正常拿到完整数组["value1", "value2"]LongValue赋值为数组首元素123
如果你用的是Newtonsoft.Json,实现逻辑完全一致,只需要继承对应框架的
JsonConverter基类实现读取逻辑、加入序列化配置即可。
内容的提问来源于stack exchange,提问作者Gabe
相关产品推荐
相关产品推荐

