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

Dart:在泛型类模板中用命名构造函数实现多类反序列化

实现统一泛型序列化/反序列化列表的解决方案

你需要实现一套统一的泛型接口,处理Serializable子类的列表序列化与反序列化,避免为每种类型编写自定义列表反序列化逻辑,但当前代码因Dart不支持抽象静态方法、无法通过泛型类型直接调用构造函数而报错,以下是两种可行的解决方案:


方案一:给Schema传入反序列化工厂函数

通过将具体类型的反序列化逻辑(如User.fromMap)作为参数传入Schema,让Schema明确知晓如何将Map转换为对应对象,无需依赖抽象静态方法。

修正后的完整代码:

abstract class Serializable {
  // 仅保留序列化方法
  Map<String, dynamic> toMap();
}

class Schema<T extends Serializable> {
  // 存储当前类型的反序列化工厂函数
  final T Function(Map<String, dynamic>) _fromMap;
  List<T> data = [];

  // 构造时传入对应类型的反序列化逻辑
  Schema(this._fromMap);

  List<Map<String, dynamic>> serialize() {
    return data.map((e) => e.toMap()).toList();
  }

  void deserialize(List<Map<String, dynamic>> inputData) {
    this.data = inputData.map(_fromMap).toList();
  }
}

// 具体实现类
class User extends Serializable {
  String username;

  User(this.username);

  @override
  Map<String, dynamic> toMap() {
    return {'username': username};
  }

  // 定义类型专属的反序列化工厂方法
  factory User.fromMap(Map<String, dynamic> map) {
    return User(map['username'] as String);
  }
}

// 使用示例
void main() {
  final usersSchema = Schema<User>(User.fromMap);
  // 模拟从JSON解析得到的Map列表
  final rawData = [{'username': 'alice'}, {'username': 'bob'}];
  usersSchema.deserialize(rawData);
  print(usersSchema.data.map((u) => u.username)); // 输出: (alice, bob)
}

方案优势:

  • 逻辑直观,每个Schema实例明确绑定对应类型的反序列化规则
  • 无全局状态,避免类型冲突
  • 符合依赖注入的设计思想

方案二:全局构造器注册器

如果需要集中管理所有Serializable类型的反序列化逻辑,可以通过静态注册中心存储类型与构造器的映射,Schema直接从注册中心获取反序列化方法,无需每次传入工厂函数。

完整代码示例:

abstract class Serializable {
  Map<String, dynamic> toMap();
  
  // 全局注册中心:存储类型到反序列化构造器的映射
  static final Map<Type, dynamic Function(Map<String, dynamic>)> _constructorRegistry = {};

  // 注册类型的反序列化构造器
  static void register<T extends Serializable>(T Function(Map<String, dynamic>) constructor) {
    _constructorRegistry[T] = constructor;
  }

  // 全局反序列化方法,根据类型匹配构造器
  static T fromMap<T extends Serializable>(Map<String, dynamic> map) {
    final constructor = _constructorRegistry[T];
    if (constructor == null) {
      throw StateError('Type $T has not been registered.');
    }
    return constructor(map) as T;
  }
}

class Schema<T extends Serializable> {
  List<T> data = [];

  List<Map<String, dynamic>> serialize() {
    return data.map((e) => e.toMap()).toList();
  }

  void deserialize(List<Map<String, dynamic>> inputData) {
    this.data = inputData.map((map) => Serializable.fromMap<T>(map)).toList();
  }
}

// 具体实现类
class User extends Serializable {
  String username;

  User(this.username);

  @override
  Map<String, dynamic> toMap() {
    return {'username': username};
  }

  factory User.fromMap(Map<String, dynamic> map) {
    return User(map['username'] as String);
  }
}

// 使用示例
void main() {
  // 提前注册User的反序列化构造器
  Serializable.register(User.fromMap);
  
  final usersSchema = Schema<User>();
  final rawData = [{'username': 'charlie'}, {'username': 'david'}];
  usersSchema.deserialize(rawData);
  print(usersSchema.data.map((u) => u.username)); // 输出: (charlie, david)
}

方案优势:

  • 无需在创建Schema时重复传入工厂函数
  • 适合需要集中管理所有可序列化类型的场景

原代码的核心问题说明:

  1. Dart不支持抽象命名构造函数,也不允许子类重写父类的命名构造函数,因此原代码中Serializable.fromMap作为抽象命名构造函数无效,子类的@override标注也是错误的。
  2. 泛型类型T在运行时会被类型擦除,且T是Type类型而非具体实例,无法直接调用T.fromMap构造函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 09:40:30