如何将JSON反序列化为父类的正确派生类型?
解决Json.NET反序列化子类字段丢失的问题
嘿,我来帮你搞定这个问题!你遇到的情况很典型——当你用基类Parent去反序列化FirstChild或SecondChild的JSON时,默认情况下Json.NET只会识别基类的字段,子类的属性直接就丢失了。而且你提到没法控制序列化过程,那之前用TypeNameHandling.All的思路肯定走不通,因为这个设置需要序列化阶段就把类型标识(比如$type字段)写入JSON,而你完全没法干预那一步。
咱们换个思路:不用你手动检查JSON内容,而是让反序列化过程自动识别子类独有的字段,判断该实例化哪个类型——这个逻辑会封装在转换器里,对你来说是完全透明的。
解决方案:自定义JsonConverter
核心是写一个自定义的JsonConverter,让它在反序列化时自动检查JSON里的字段,判断应该实例化FirstChild还是SecondChild,再完成反序列化。
1. 实现自定义转换器
public class ParentConverter : JsonConverter { public override bool CanConvert(Type objectType) { // 只处理Parent及其子类的转换 return objectType == typeof(Parent); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // 先把JSON加载成JObject,方便检查字段 var jObject = JObject.Load(reader); // 根据子类独有的字段判断类型:有firstName就是FirstChild,有lastName就是SecondChild if (jObject.ContainsKey("firstName")) { return jObject.ToObject<FirstChild>(serializer); } else if (jObject.ContainsKey("lastName")) { return jObject.ToObject<SecondChild>(serializer); } // 都不符合的话,返回基类实例 return jObject.ToObject<Parent>(serializer); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // 序列化用默认逻辑就行,不需要自定义 serializer.Serialize(writer, value); } }
2. 使用转换器反序列化
// 创建序列化设置,添加自定义转换器 var settings = new JsonSerializerSettings(); settings.Converters.Add(new ParentConverter()); // 测试FirstChild的JSON var firstChildJson = "{\"firstName\":\"John\",\"id\":\"1\"}"; var deserialized = JsonConvert.DeserializeObject<Parent>(firstChildJson, settings); // 现在可以正确识别子类类型,访问子类字段 if (deserialized is FirstChild firstChild) { Console.WriteLine($"First Name: {firstChild.FirstName}, ID: {firstChild.Id}"); } // 测试SecondChild的JSON var secondChildJson = "{\"lastName\":\"Doe\",\"id\":\"2\"}"; deserialized = JsonConvert.DeserializeObject<Parent>(secondChildJson, settings); if (deserialized is SecondChild secondChild) { Console.WriteLine($"Last Name: {secondChild.LastName}, ID: {secondChild.Id}"); }
关键说明
- 这个方案完全不需要控制序列化过程:不管JSON是怎么生成的,只要子类有独有的字段,转换器就能自动识别。
- 扩展性强:以后如果新增
ThirdChild,只需要在ReadJson方法里加一个字段判断分支就行。 - 大小写兼容:Json.NET默认会自动处理JSON里的小驼峰(比如
firstName)和C#类里的大驼峰(比如FirstName)的映射,不用额外配置。
内容的提问来源于stack exchange,提问作者Yahya Hussein
相关产品推荐
相关产品推荐

