如何获取对象所属类并将存储的JSON反序列化为对应对象?
解决方案:序列化/反序列化LogBase子类并还原类型
这问题我之前处理过类似的离线重试场景,核心就是要在序列化时把具体子类的类型信息一起持久化,这样后续反序列化才能准确还原成LogStart或LogViews实例。下面给你一步步拆解实现方案:
一、存储待重放日志时,同步保存类型信息
你需要在本地数据库中存储两个关键信息:
- 序列化后的JSON字符串
- 日志对象对应的完整类型名称(包含程序集信息,避免同名类冲突)
示例代码如下:
public void SaveLogForRetry(LogBase item) { // 序列化LogBase子类实例为JSON string jsonContent = JsonConvert.SerializeObject(item); // 获取对象的完整类型名称(AssemblyQualifiedName包含程序集信息,确保类型唯一) string typeName = item.GetType().AssemblyQualifiedName; // 将jsonContent和typeName存入本地数据库(示例用伪代码,根据你的数据库类型调整) // 比如用SQLite: // await localDatabase.ExecuteAsync( // "INSERT INTO PendingLogs (JsonContent, TypeName, CreatedTime) VALUES (@Json, @Type, @Time)", // new { Json = jsonContent, Type = typeName, Time = DateTime.UtcNow } // ); }
二、重放日志时,通过类型信息反序列化还原对象
从本地数据库取出存储的JSON和类型名称后,先通过Type.GetType()获取对应的类型,再用Json.NET的重载方法反序列化:
示例代码如下:
public async Task<bool> ReplayPendingLog(int pendingLogId) { // 从本地数据库获取待重放的日志记录 var pendingLog = await localDatabase.QueryFirstAsync<PendingLog>( "SELECT JsonContent, TypeName FROM PendingLogs WHERE Id = @Id", new { Id = pendingLogId } ); // 根据存储的类型名称获取Type对象 Type logType = Type.GetType(pendingLog.TypeName); if (logType == null) { // 处理类型找不到的异常场景(比如程序集版本变更) // 建议记录错误日志,避免无限重试 throw new InvalidOperationException($"无法找到指定类型:{pendingLog.TypeName}"); } // 反序列化为对应的LogBase子类实例 LogBase logItem = (LogBase)JsonConvert.DeserializeObject(pendingLog.JsonContent, logType); // 调用原方法插入到远程数据库 await client.CreateDocumentAsync(collectionLink, logItem); // 重放成功后,删除本地的待重放记录 await localDatabase.ExecuteAsync( "DELETE FROM PendingLogs WHERE Id = @Id", new { Id = pendingLogId } ); return true; } // 辅助类:对应本地数据库的PendingLogs表结构 public class PendingLog { public int Id { get; set; } public string JsonContent { get; set; } public string TypeName { get; set; } public DateTime CreatedTime { get; set; } }
三、额外优化建议
- 类型名称的选择:如果觉得
AssemblyQualifiedName太长,也可以存储Type.FullName(类的完整命名空间+类名),但AssemblyQualifiedName更可靠,能避免不同程序集中同名类的冲突。 - 异常处理:在反序列化和远程调用过程中,要捕获网络异常、序列化异常等,增加重试次数限制、过期时间,防止无效重试占用资源。
- 备选方案:如果你的子类数量固定且不多,可以给
LogBase添加[KnownType]属性(比如[KnownType(typeof(LogStart))]),这样序列化时会自动携带类型信息,但灵活性不如手动存储类型名称。
内容的提问来源于stack exchange,提问作者Alan2
相关产品推荐
相关产品推荐

