C#使用JavaScriptSerializer反序列化派生类集合仅得到基类实例如何解决
问题原因
转换失败是因为JavaScriptSerializer默认反序列化逻辑仅会创建你指定的声明类型(也就是List<AutoEvent>里的AutoEvent)的实例,不会主动识别JSON中包含的派生类独有字段,所以反序列化得到的所有元素都是基类实例,自然没有派生类的成员,强转也会抛出运行时异常。
解决方案
方案1:继续使用JavaScriptSerializer(自定义转换器)
通过实现自定义的JavaScriptConverter,手动判断JSON对应的实际派生类类型并创建对应实例。
步骤1:实现自定义转换器
public class AutoEventConverter : JavaScriptConverter { public override IEnumerable<Type> SupportedTypes { get { return new List<Type> { typeof(AutoEvent) }; } } public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) { // 通过派生类独有字段判断实际类型 if (dictionary.ContainsKey("RectArea")) { return serializer.ConvertToType<MouseClickEvent>(dictionary); } if (dictionary.ContainsKey("ImgTolerance")) { return serializer.ConvertToType<ClickImageEvent>(dictionary); } // 无匹配字段返回基类实例 return serializer.ConvertToType<AutoEvent>(dictionary); } public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { // 序列化逻辑无需修改,返回空字典走默认序列化逻辑即可 return new Dictionary<string, object>(); } }
步骤2:注册转换器后执行序列化/反序列化
在创建JavaScriptSerializer实例后,先注册自定义转换器再执行后续操作:
JavaScriptSerializer ser = new JavaScriptSerializer(); // 注册自定义派生类转换器 ser.RegisterConverters(new List<JavaScriptConverter> { new AutoEventConverter() }); // 原有序列化、反序列化逻辑保持不变即可 string json = ser.Serialize(events); // ... 读写文件逻辑 events = ser.Deserialize<List<AutoEvent>>(json);
方案2:改用Newtonsoft.Json(更推荐)
Newtonsoft.Json(Json.NET)是.NET生态最常用的JSON处理库,原生支持多态类型序列化/反序列化,无需手动写转换器。
步骤1:安装依赖
在NuGet包管理器中安装Newtonsoft.Json,或执行包管理器命令:Install-Package Newtonsoft.Json
步骤2:修改序列化/反序列化逻辑
配置TypeNameHandling参数,让Json.NET自动在JSON中存储类型信息,反序列化时自动识别创建对应派生类实例:
// 序列化 string json = JsonConvert.SerializeObject(events, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); // 写文件逻辑不变 File.WriteAllText(path, json); // 反序列化 json = File.ReadAllText(path); events = JsonConvert.DeserializeObject<List<AutoEvent>>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
注意:如果JSON来源于不可信环境,使用
TypeNameHandling存在类型注入风险,仅在内部可信场景下使用该配置即可。
内容的提问来源于stack exchange,提问作者Nenad Birešev
相关产品推荐
相关产品推荐

