Dart泛型场景下fromJson调用报错,如何实现通用的fromJson/toJson?
问题分析
Dart 中泛型类型参数 T 本质是 Type 对象,无法直接调用类的静态方法或工厂构造方法。尽管你的子类都重写了 fromJson 工厂构造,但泛型约束 T extends TestClass 仅保证 T 是 TestClass 的子类,而工厂构造属于类级成员,不属于实例继承范畴,因此编译器无法推断所有 T 类型都具备 fromJson 方法,从而报错。
解决方案
方案1:给方法传入 fromJson 回调函数
修改 FactoryController 的 listNetworkObjects 方法,新增一个接收 Map 并返回 T 的回调参数,直接传入对应子类的 fromJson 工厂构造:
class FactoryController{ Future<List<T>> listNetworkObjects<T extends TestClass>({ required List<String> filters, required T Function(Map<String, dynamic>) fromJson, // 新增回调参数 }) async { try { final data = await MockApi().mockApiCall(filters); // 将API返回的列表数据逐个转换为T实例 final List<T> allItems = (data as List).map((json) { return fromJson(json as Map<String, dynamic>); }).toList(); if (allItems.isNotEmpty) { print('Received Items from the API.'); } return allItems; } catch (getTestClassError, stackTrace) { print('Error getting TestClasses'); print(stackTrace); return <T>[]; } } }
调用示例:
final controller = FactoryController(); // 获取ATest列表 controller.listNetworkObjects<ATest>( filters: ['filter1'], fromJson: ATest.fromJson, ); // 获取BTest列表 controller.listNetworkObjects<BTest>( filters: ['filter2'], fromJson: BTest.fromJson, );
方案2:将 fromJson 回调注入到控制器实例
如果不想每次调用方法都传回调,可以在 FactoryController 初始化时传入 fromJson,绑定到特定子类:
class FactoryController<T extends TestClass>{ final T Function(Map<String, dynamic>) _fromJson; // 构造器注入回调 FactoryController(this._fromJson); Future<List<T>> listNetworkObjects({ required List<String> filters, }) async { try { final data = await MockApi().mockApiCall(filters); final List<T> allItems = (data as List).map((json) { return _fromJson(json as Map<String, dynamic>); }).toList(); if (allItems.isNotEmpty) { print('Received Items from the API.'); } return allItems; } catch (getTestClassError, stackTrace) { print('Error getting TestClasses'); print(stackTrace); return <T>[]; } } }
调用示例:
// 创建绑定ATest的控制器 final aController = FactoryController<ATest>(ATest.fromJson); aController.listNetworkObjects(filters: ['filter1']); // 创建绑定BTest的控制器 final bController = FactoryController<BTest>(BTest.fromJson); bController.listNetworkObjects(filters: ['filter2']);
补充:修正MockApi返回格式
原 MockApi 返回单个 Map,不符合列表数据场景,建议修改为返回列表:
class MockApi{ MockApi(); Future<List<Map<String, dynamic>>> mockApiCall(List<String> filters) async { // 模拟API返回多个数据项 return [{"test": "object1"}, {"test": "object2"}]; } }
内容的提问来源于stack exchange,提问作者Quentin Kramer
相关产品推荐
相关产品推荐

