如何让System.Text.Json复用已有属性实现多态序列化与反序列化?
解决办法
方案1:标记基类Type属性为忽略,自动同步类型名称
修改基类的Type属性,用[JsonIgnore]标记避免序列化输出,同时让属性值自动匹配当前对象的类型名称,无需手动赋值:
public class Foo { public int Id { get; set; } [JsonIgnore] public string Type { get => GetType().Name; set { } // 空setter避免反序列化时出错 } }
此方案下,多态机制生成的Type鉴别器会正常输出,反序列化后对象的Type属性会自动获取正确的类型名称,无需额外处理。
方案2:自定义转换器处理重复属性
创建自定义JsonConverter,序列化时只输出一次Type属性,反序列化时忽略重复字段:
public class FooConverter : JsonConverter<Foo> { public override Foo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using JsonDocument doc = JsonDocument.ParseValue(ref reader); JsonElement root = doc.RootElement; string typeName = root.GetProperty("Type").GetString()!; Type targetType = typeName switch { nameof(Foo) => typeof(Foo), nameof(Bar) => typeof(Bar), _ => throw new JsonException($"未知类型: {typeName}") }; // 反序列化为目标类型 return (Foo)JsonSerializer.Deserialize(root.GetRawText(), targetType, options)!; } public override void Write(Utf8JsonWriter writer, Foo value, JsonSerializerOptions options) { writer.WriteStartObject(); // 只写入一次Type属性,使用对象自身的Type值 writer.WriteString("Type", value.Type); writer.WriteNumber("Id", value.Id); // 处理派生类的额外属性 if (value is Bar bar) { writer.WriteString("BarSpecificProperty", bar.BarSpecificProperty); } writer.WriteEndObject(); } }
然后在序列化配置中添加转换器:
var options = new JsonSerializerOptions { WriteIndented = true, Converters = { new FooConverter() } };
方案3:修改鉴别器字段名(简单但不推荐)
如果可以接受鉴别器字段名与基类属性名不同,直接修改TypeDiscriminatorPropertyName为其他名称(如$type),避免重复:
typeInfo.PolymorphismOptions = new JsonPolymorphismOptions { TypeDiscriminatorPropertyName = "$type", // 使用不同名称 DerivedTypes = { new JsonDerivedType(typeof(Foo), nameof(Foo)), new JsonDerivedType(typeof(Bar), nameof(Bar)), }, };
此方案无需修改基类,但会改变JSON结构,不符合复用已有Type属性的需求。
内容的提问来源于stack exchange,提问作者vmachacek
相关产品推荐
相关产品推荐

