如何使用Json.NET序列化反序列化多态列表并保留对象继承类型
解决方案
你遇到的问题本质是Newtonsoft.Json默认不会在序列化时记录对象的实际类型信息,反序列化时只会按照你指定的List<Location>的元素类型Location构造实例,自然丢失了子类的属性和重写逻辑。可以通过两种方式解决:
方法1:使用内置的TypeNameHandling配置(最简单)
在序列化和反序列化时都指定TypeNameHandling参数,框架会自动给多态对象增加$type元字段记录实际类型,反序列化时自动恢复对应的子类实例。
序列化代码修改
File.WriteAllText(@"serialized.json", JsonConvert.SerializeObject(locations, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }));
TypeNameHandling.Auto只会在声明类型和实际类型不一致时写入类型信息,不会产生冗余数据。
反序列化代码修改
var stuff = JsonConvert.DeserializeObject<List<Location>>(File.ReadAllText("serialized.json"), new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
方法2:自定义JsonConverter(更安全,适合不可信JSON来源)
如果你的JSON文件来自外部不可信来源,TypeNameHandling存在反序列化攻击风险,你可以手动写转换器判断类型:
public class LocationConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(Location); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jo = JObject.Load(reader); // 子类独有的flag字段作为判断依据 if (jo.ContainsKey("flag")) { return jo.ToObject<FlaggedLocation>(serializer); } return jo.ToObject<Location>(serializer); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
反序列化时传入转换器即可,不需要修改序列化逻辑:
var stuff = JsonConvert.DeserializeObject<List<Location>>(File.ReadAllText("serialized.json"), new LocationConverter());
额外注意
你贴的代码里存在几处语法错误,需要先修正才能正常运行:
- FlaggedLocation构造函数调用父类构造时,缺少了
List<string> adjacents参数,你测试代码里实例化Location、FlaggedLocation时也漏传了该参数 - FlaggedLocation的
GetAppropriateText重写方法里,AlternateEntrytext拼写和属性定义的AlternateEntryText大小写不一致,else分支也缺少return关键字
内容的提问来源于stack exchange,提问作者johnnymcmike
相关产品推荐
相关产品推荐

