.NET Core System.Text.Json保留引用序列化丢失派生类属性如何解决
问题根因
默认情况下System.Text.Json序列化时会使用属性的声明类型而非运行时实际类型来扫描要序列化的字段,结合引用保留配置时,先被序列化的基类声明属性只会序列化基类字段,后续同实例的派生类属性就会直接引用已序列化的不完整对象,导致字段丢失、反序列化失败。
解决方案
方案1:使用JsonDerivedType特性(推荐,适用于.NET 7+)
直接在基类Employee上标注所有允许的派生类型,System.Text.Json序列化时会自动识别运行时实际类型,序列化完整的派生类属性:
using System.Text.Json.Serialization; [JsonDerivedType(typeof(Manager))] public class Employee { public string Name { get; set; } public int Age { get; set; } }
添加该特性后无需修改原有业务逻辑,序列化时EmployeeOfTheMonth就会按实际的Manager类型序列化,完整保留AllowedPersonalDays属性,反序列化也不会抛出类型转换异常。
方案2:自定义基类JsonConverter(兼容所有.NET版本)
如果使用的是.NET 6及更早版本,不支持JsonDerivedType特性,可以自定义Employee类型的转换器,强制序列化/反序列化时使用运行时实际类型处理:
using System.Text.Json; using System.Text.Json.Serialization; public class EmployeeConverter : JsonConverter<Employee> { public override Employee Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); // 判断是否包含Manager独有属性,选择对应类型反序列化 if (doc.RootElement.TryGetProperty(nameof(Manager.AllowedPersonalDays), out _)) { return doc.Deserialize<Manager>(options); } return doc.Deserialize<Employee>(options); } public override void Write(Utf8JsonWriter writer, Employee value, JsonSerializerOptions options) { // 按运行时实际类型序列化 JsonSerializer.Serialize(writer, value, value.GetType(), options); } }
之后把转换器添加到序列化配置中即可:
System.Text.Json.JsonSerializerOptions options = new System.Text.Json.JsonSerializerOptions(); options.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve; options.Converters.Add(new EmployeeConverter()); // 新增转换器注册
方案3:修改属性声明类型为object(临时适配,不推荐)
如果不想修改基类或新增转换器,可以把Store类中EmployeeOfTheMonth的声明类型改为object,System.Text.Json序列化object类型时会默认使用运行时实际类型处理,但该方案会丢失编译期类型检查,仅适合临时快速适配场景。
内容的提问来源于stack exchange,提问作者Trecius Veil
相关产品推荐
相关产品推荐

