当构造函数参数与属性类型不匹配时,如何让System.Text.Json正确反序列化?
构造函数参数与同名属性类型不匹配时,System.Text.Json的最优反序列化方案
你的场景中,Data类的构造函数参数ints为IEnumerable<int>类型,对应属性Ints是IReadOnlyCollection<int>类型,这种类型不匹配导致System.Text.Json(STJ)反序列化失败,而Newtonsoft.Json可正常处理。以下是几种最优解决思路:
方案一:调整构造函数参数类型适配STJ默认序列化逻辑
STJ会默认将JSON数组反序列化为List<T>,让构造函数参数类型与该默认类型匹配,即可完成绑定,再在构造函数内转换为目标只读集合类型:
using System.Text.Json; using System.Text.Json.Serialization; string data = """ { "Ints": [24, 43, 54, 23] } """; var parsed = JsonSerializer.Deserialize<Data>(data)!; class Data { // 显式标记反序列化构造函数,参数类型改为List<int> [JsonConstructor] public Data(List<int> ints) { Ints = ints.AsReadOnly(); } public IReadOnlyCollection<int> Ints { get; } }
这种方案最简单直接,无需额外编写转换器,完全利用STJ的原生绑定规则。
方案二:自定义JsonConverter处理类型转换
如果不想修改构造函数参数类型,可以编写自定义转换器,通过临时对象中转反序列化结果:
using System.Text.Json; using System.Text.Json.Serialization; string data = """ { "Ints": [24, 43, 54, 23] } """; var options = new JsonSerializerOptions { Converters = { new DataConverter() } }; var parsed = JsonSerializer.Deserialize<Data>(data, options)!; class Data { public Data(IEnumerable<int> ints) { Ints = ints.ToList().AsReadOnly(); } public IReadOnlyCollection<int> Ints { get; } } class DataConverter : JsonConverter<Data> { public override Data? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 先反序列化为临时对象接收原始数组 var temp = JsonSerializer.Deserialize<DataTemp>(ref reader, options); return temp != null ? new Data(temp.Ints) : null; } public override void Write(Utf8JsonWriter writer, Data value, JsonSerializerOptions options) { // 序列化时直接输出只读集合内容 JsonSerializer.Serialize(writer, new { value.Ints }, options); } // 临时类适配STJ默认序列化逻辑 private class DataTemp { public List<int> Ints { get; set; } = new(); } }
该方案灵活性高,适合无法修改目标类构造函数的场景。
异常原因说明
你遇到的异常信息翻译如下:
System.InvalidOperationException:
类型'Data'的反序列化构造函数中的每个参数必须在反序列化时绑定到对象的属性或字段。
每个参数名称必须与对象的属性或字段匹配。
只有启用'JsonSerializerOptions.IncludeFields'时才会考虑字段。
匹配可以不区分大小写。
STJ的构造函数绑定规则要求参数类型需与属性/字段的序列化兼容类型一致,IEnumerable<int>与IReadOnlyCollection<int>虽有继承关系,但STJ无法自动完成这种跨类型的绑定映射,因此需要手动调整。
内容的提问来源于stack exchange,提问作者QmlnR2F5
相关产品推荐
相关产品推荐

