System.Text.Json多态序列化问题:子类自定义属性无法序列化
解决System.Text.Json多态序列化问题(抽象类无法序列化子类自定义属性)
当使用System.Text.Json序列化包含抽象类属性的对象时,默认只会序列化抽象类定义的属性,子类的自定义属性会丢失。由于抽象类SubData位于独立包中,无法提前通过[JsonDerivedType]特性注册所有可能的派生类,以下是几种可行的动态多态序列化方案:
方案一:自定义JsonConverter处理多态序列化
通过实现JsonConverter<SubData>,在序列化时使用子类的实际类型进行序列化,同时可添加类型鉴别器字段用于反序列化。
public class SubDataConverter : JsonConverter<SubData> { // 反序列化逻辑(服务端需要时实现) public override SubData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); if (!doc.RootElement.TryGetProperty("$type", out var typeElement)) throw new JsonException("缺少类型鉴别器$type"); var targetType = Type.GetType(typeElement.GetString()); if (targetType == null || !typeof(SubData).IsAssignableFrom(targetType)) throw new JsonException("无法识别的派生类型"); return (SubData)JsonSerializer.Deserialize(doc.RootElement.GetRawText(), targetType, options); } // 序列化逻辑 public override void Write(Utf8JsonWriter writer, SubData value, JsonSerializerOptions options) { var actualType = value.GetType(); writer.WriteStartObject(); // 添加类型鉴别器,用于反序列化识别子类 writer.WriteString("$type", actualType.AssemblyQualifiedName); // 序列化子类的所有属性 var element = JsonSerializer.SerializeToElement(value, actualType, options); foreach (var prop in element.EnumerateObject()) { prop.WriteTo(writer); } writer.WriteEndObject(); } }
使用方式:
void SerializData(Data data) { var options = new JsonSerializerOptions { Converters = { new SubDataConverter() } }; var serialized = JsonSerializer.Serialize(data, options); // 此时serialized包含ExtendedSubData的Prop3属性及$type字段 }
方案二:通过TypeInfoResolver动态注册派生类型
利用DefaultJsonTypeInfoResolver在运行时动态为抽象类添加派生类型,无需修改独立包中的SubData类。
用户在自己的代码中配置序列化选项:
void SerializData(Data data) { var options = new JsonSerializerOptions { TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { typeInfo => { // 针对SubData类配置多态 if (typeInfo.Type == typeof(SubData)) { // 注册用户自定义的派生类 typeInfo.PolymorphismOptions.DerivedTypes.Add( new JsonDerivedType(typeof(ExtendedSubData), "ExtendedSubData")); // 设置类型鉴别器的属性名,默认是$type typeInfo.PolymorphismOptions.TypeDiscriminatorPropertyName = "type"; } } } } }; var serialized = JsonSerializer.Serialize(data, options); }
该方案适合用户能够控制序列化配置的场景,无需自定义转换器,利用框架内置的多态支持。
方案三:修复序列化泛型类型错误
原代码中使用JsonSerializer.Serialize<object>(data)会导致序列化时丢失具体类型信息,应直接序列化Data类型:
void SerializData(Data data) { // 配合方案一或方案二的options使用 var options = new JsonSerializerOptions(); // 添加转换器或多态配置... var serialized = JsonSerializer.Serialize(data, options); }
方案选择建议
- 如果需要服务端反序列化子类对象,方案一更灵活,无需提前注册所有派生类,但需要处理类型字符串解析。
- 如果用户可以自主配置序列化选项,方案二更简洁,符合System.Text.Json的原生多态设计。
- 无论采用哪种方案,都要避免将序列化泛型类型指定为
object,否则会丢失类型元数据。
内容的提问来源于stack exchange,提问作者Ivan Pavić
相关产品推荐
相关产品推荐

