如何使用Newtonsoft.Json反序列化接口类型的列表?
解决接口类型反序列化的JsonSerializationException问题
核心问题
Json.NET无法实例化接口(IAccount、ITask),当前反序列化未配置类型信息读取逻辑,同时Room类缺少无参构造、部分属性/字段的序列化反序列化逻辑存在冲突,导致报错。
具体解决方案
1. 反序列化时同步配置TypeNameHandling
在反序列化代码中添加与序列化一致的TypeNameHandling.Auto配置,让Json.NET能读取序列化时写入的类型标记,明确要实例化的具体类:
public List<IAccount> DeserealiseRoom(string list) { path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, list); if (File.Exists(path)) { var file = File.ReadAllText(path); return JsonConvert.DeserializeObject<List<IAccount>>(file, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, TypeNameHandling = TypeNameHandling.Auto }); } return null; }
2. 为Room类添加无参构造函数
Json.NET默认需要无参构造来实例化对象,Room目前只有带参数的构造,可通过以下两种方式处理:
- 方式1:添加公开无参构造
public Room() { }
- 方式2:添加私有无参构造,并在反序列化配置中允许使用非公共默认构造
// Room类中添加私有构造 private Room() { } // 反序列化配置中追加 ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
3. 忽略tasksToDo属性的序列化/反序列化
tasksToDo是动态从factory获取的只读属性,无需序列化,标记为忽略避免接口类型的额外报错:
[JsonIgnore] public List<ITask> tasksToDo { get { return factory.manager.tasks.FindAll(w => w.claimer == this); } }
4. 处理Factory私有字段的序列化问题
私有factory字段无法被Json.NET序列化,且反序列化后无法自动赋值,会导致Room依赖factory的属性失效:
- 标记
factory为忽略序列化:
[JsonIgnore] private Factory factory { get; set; }
- 反序列化后手动为
Room实例注入factory:
// 反序列化完成后 var accounts = JsonConvert.DeserializeObject<List<IAccount>>(file, settings); foreach (var room in accounts.OfType<Room>()) { room.SetFactory(yourFactoryInstance); // 需要为Room添加对应的方法 } // Room类中添加方法 public void SetFactory(Factory factory) { this.factory = factory; }
验证生效
序列化后的JSON应包含$type标记,示例如下:
[ { "$type": "YourNamespace.Room, YourAssembly", "login": { ... }, "isOccupied": true, "id": 1, "json": { ... } } ]
确保该标记存在,反序列化时即可正确识别具体类型。
内容的提问来源于stack exchange,提问作者CitrusBoy
相关产品推荐
相关产品推荐

