System.Text.Json:如何反序列化含接口属性的类(.NET 6)
从Newtonsoft迁移到System.Text.Json:接口属性反序列化的简化方案
问题描述
我正在从Newtonsoft迁移至System.Text.Json,Newtonsoft可自动反序列化包含接口属性的对象,但使用System.Text.Json时会抛出如下错误:
each parameter in the deserialization constructor must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object.
编写自定义转换器能规避该问题,但面对多层嵌套的接口属性(每层接口属性又包含多个接口属性),需要编写大量转换器,开销太大。有没有更简便的解决方案?
示例代码
[Fact] public void JsonTest() { var child = new Child(new Name("Peter"), 10); var parent = new Parent(child); var str = JsonSerializer.Serialize(parent); var jsonObj = JsonSerializer.Deserialize<Parent>(str); Console.WriteLine(jsonObj!.Child.Name); } public class Parent { public Parent(Child child) { Child = child; } public IChild Child { get; set;} } public class Child : IChild { [JsonConstructor] public Child(Name name, int age) { Name = name; Age = age; } public IName Name { get; set; } public int Age { get; set; } } public class Name : IName { public string NameValue { get; set; } public Name(string nameValue) { NameValue = nameValue; } } public interface IChild { IName Name { get; } int Age { get; } } public interface IName { string NameValue { get; } }
简化解决方案
方案1:对齐构造函数参数与属性名
System.Text.Json的构造函数绑定要求参数名与属性名严格匹配(默认大小写敏感)。只需调整构造函数参数名,使其对应属性名一致,再配合大小写不敏感配置即可:
修改Parent类构造函数:
public class Parent { // 参数名改为Child,与属性名一致 public Parent(Child Child) { this.Child = Child; } public IChild Child { get; set;} }
反序列化时启用大小写不敏感:
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var jsonObj = JsonSerializer.Deserialize<Parent>(str, options);
方案2:通用接口转换器(批量处理接口-实现类映射)
编写一个泛型转换器,预先注册所有接口与对应实现类的映射,一次性处理所有嵌套场景,无需为每个类单独写转换器:
public class InterfaceConverter<TInterface, TImplementation> : JsonConverter<TInterface> where TImplementation : class, TInterface { public override TInterface Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return JsonSerializer.Deserialize<TImplementation>(ref reader, options)!; } public override void Write(Utf8JsonWriter writer, TInterface value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, (TImplementation)value, options); } }
使用时在配置中注册映射:
var options = new JsonSerializerOptions { Converters = { new InterfaceConverter<IChild, Child>(), new InterfaceConverter<IName, Name>() } }; // 序列化与反序列化均使用该配置 var str = JsonSerializer.Serialize(parent, options); var jsonObj = JsonSerializer.Deserialize<Parent>(str, options);
方案3:为实现类添加无参数构造函数(适用于可变对象)
如果业务允许,给实现类添加无参数构造函数,同时确保属性可写,System.Text.Json会自动完成反序列化:
public class Name : IName { public string NameValue { get; set; } // 添加无参数构造函数 public Name() {} public Name(string nameValue) { NameValue = nameValue; } }
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

