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

使用Dart将含对象的Map序列化为JSON时遇错求助

解决Dart中json_serializable序列化Map<自定义对象, 值>的问题

你遇到的错误核心原因是JSON规范不支持非字符串类型作为对象的键,直接序列化Map<PlayerModel, double>时,PlayerModel无法被识别为合法的JSON键,因此抛出JsonUnsupportedObjectError。下面提供两种可行的解决方案:

方案一:将Map转换为包含完整Player信息的数组(推荐,无需依赖外部数据)

这种方式把原Map结构转换成JSON支持的数组格式,每个元素包含Player的完整JSON数据和对应分数,序列化后可以独立还原,无需依赖外部的Player数据源。

修改BoardDataConverter的实现:

class BoardDataConverter implements JsonConverter<Map<PlayerModel, double>, List<dynamic>> {
  const BoardDataConverter();

  @override
  Map<PlayerModel, double> fromJson(List<dynamic> jsonList) {
    final Map<PlayerModel, double> result = {};
    for (final item in jsonList) {
      final player = PlayerModel.fromJson(item['player'] as Map<String, dynamic>);
      final score = item['score'] as double;
      result[player] = score;
    }
    return result;
  }

  @override
  List<dynamic> toJson(Map<PlayerModel, double> data) {
    return data.entries.map((entry) => {
      'player': entry.key.toJson(),
      'score': entry.value,
    }).toList();
  }
}

修改后,boardData字段的注解保持不变,重新运行build_runner更新生成文件:

flutter pub run build_runner build

方案二:用Player的唯一ID作为JSON键(适合已有Player数据源的场景)

如果你的业务中已经有全局的Player列表/缓存,可以用Player的id(唯一标识)作为JSON中的键,节省存储空间,但反序列化时需要根据ID还原Player实例。

修改BoardDataConverter的实现:

class BoardDataConverter implements JsonConverter<Map<PlayerModel, double>, Map<String, dynamic>> {
  const BoardDataConverter();

  // 需实现根据ID获取PlayerModel的逻辑(比如从数据库/缓存中查询)
  PlayerModel _getPlayerById(String id) {
    // 示例逻辑,根据实际业务替换
    // return PlayerCache.instance.getPlayer(id);
    throw UnimplementedError('请实现根据ID获取PlayerModel的方法');
  }

  @override
  Map<PlayerModel, double> fromJson(Map<String, dynamic> jsonMap) {
    final Map<PlayerModel, double> result = {};
    for (final entry in jsonMap.entries) {
      final player = _getPlayerById(entry.key);
      final score = entry.value as double;
      result[player] = score;
    }
    return result;
  }

  @override
  Map<String, dynamic> toJson(Map<PlayerModel, double> data) {
    final Map<String, double> jsonMap = {};
    for (final entry in data.entries) {
      jsonMap[entry.key.id] = entry.value;
    }
    return jsonMap;
  }
}

同样,重新运行build_runner更新生成的.g文件即可。

关键注意事项

  • 无论哪种方案,都要确保PlayerModel的toJson和fromJson方法能正常工作(你的代码中已经实现,没问题)。
  • 方案一中,序列化后的JSON会包含Player的完整数据,适合需要独立存储BoardModel的场景;方案二更轻量化,但依赖外部的Player数据源。

内容的提问来源于stack exchange,提问作者CSF90

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 11:31:01