如何在.NET Json多态序列化中兼容类重命名后的旧JSON文件?
解决.NET多态JSON序列化/反序列化的类重命名兼容问题
方法1:添加多组JsonDerivedType特性(最简单方案)
直接在基类上同时保留旧类型标识与新类的映射,配合新标识的映射,即可实现反序列化兼容旧JSON,序列化输出新标识的需求。
代码示例:
[JsonDerivedType(typeof(DerivedClass1), "derivedClass1")] // 保留旧标识映射,兼容含"foo"的旧JSON [JsonDerivedType(typeof(Bar), "foo")] // 新标识用于序列化输出 [JsonDerivedType(typeof(Bar), "bar")] public abstract class BaseClass { } public class DerivedClass1 : BaseClass { } public class Bar : BaseClass { }
反序列化时,JSON中的"foo"或"bar"都会被解析为Bar类;序列化Bar实例时,会自动使用最后一组JsonDerivedType指定的"bar"作为类型标识。
方法2:自定义JsonConverter(灵活适配复杂场景)
如果需要处理多个旧标识、或有其他自定义逻辑,可编写自定义转换器接管序列化/反序列化流程:
public class BaseClassConverter : JsonConverter<BaseClass> { private readonly JsonConverter<BaseClass> _defaultConverter; public BaseClassConverter(JsonConverter<BaseClass> defaultConverter) { _defaultConverter = defaultConverter; } public override BaseClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; var discriminatorProp = options.TypeInfoResolverOptions.TypeDiscriminatorPropertyName; if (root.TryGetProperty(discriminatorProp, out var discriminator)) { if (discriminator.GetString() == "foo") { // 将旧标识替换为新标识后再反序列化 using var ms = new MemoryStream(); using var writer = new Utf8JsonWriter(ms); writer.WriteStartObject(); foreach (var prop in root.EnumerateObject()) { if (prop.Name == discriminatorProp) { writer.WriteString(prop.Name, "bar"); } else { prop.WriteTo(writer); } } writer.WriteEndObject(); writer.Flush(); ms.Position = 0; return JsonSerializer.Deserialize<BaseClass>(ms, options); } } return _defaultConverter.Read(ref reader, typeToConvert, options); } public override void Write(Utf8JsonWriter writer, BaseClass value, JsonSerializerOptions options) { // 序列化时直接使用默认逻辑,输出新标识"bar" _defaultConverter.Write(writer, value, options); } }
注册转换器的代码:
var options = new JsonSerializerOptions(); var baseTypeInfo = options.TypeInfoResolver.GetTypeInfo(typeof(BaseClass), options) as JsonTypeInfo<BaseClass>; var defaultConverter = baseTypeInfo.Converter as JsonConverter<BaseClass>; options.Converters.Add(new BaseClassConverter(defaultConverter));
方法3:配置JsonPolymorphismOptions(.NET 7+适用)
若使用.NET 7及以上版本,可通过序列化配置添加旧标识映射,无需修改类特性:
var options = new JsonSerializerOptions(); var polyOptions = options.GetTypeInfo(typeof(BaseClass)).PolymorphismOptions; // 添加旧标识到新类的映射 polyOptions.DerivedTypes.Add(new JsonDerivedType(typeof(Bar), "foo")); // 确保新标识的映射存在(若类上已配置可省略) polyOptions.DerivedTypes.Add(new JsonDerivedType(typeof(Bar), "bar"));
内容的提问来源于stack exchange,提问作者Rand Random
相关产品推荐
相关产品推荐

