You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取对象所属类并将存储的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:12:55