Dart/Flutter泛型T如何调用toJson实现通用POST数据提交
问题根因
Dart 泛型如果没有显式指定类型上限,编译器会默认泛型T的类型为Object?,无法确认传入的实例是否存在toJson()方法,因此直接调用会触发编译错误。
可落地的实现方案
方案1:泛型类型约束(轻量、类型安全,适配绝大多数场景)
先定义统一的序列化抽象接口,所有需要传入POST方法的请求实体都实现该接口,强制要求实现toJson()序列化方法:
abstract class JsonSerializable { Map<String, dynamic> toJson(); }
修改原有的postData方法,给泛型加上类型上限,明确告诉编译器所有传入的T类型都必然实现了JsonSerializable接口,一定存在可调用的toJson()方法:
Future<ReturnModel> postData<T extends JsonSerializable>(T model) async { final response = await http.post( Uri.parse('https://localhost/SomeAddress'), headers: <String, String>{ 'Content-Type': 'application/json; charset=UTF-8', }, // 此处不再报错,编译器已可识别T的toJson方法 body: jsonEncode(model.toJson()) ); if (response.statusCode == StatusCode.OK) { return ReturnModel.fromJson(jsonDecode(response.body)); } else { throw Exception('请求发生错误'); } }
后续所有请求实体类只要实现JsonSerializable接口就可以正常传入方法,举个使用示例:
// 定义请求实体 class LoginRequest implements JsonSerializable { final String username; final String password; LoginRequest({required this.username, required this.password}); @override Map<String, dynamic> toJson() { return { 'username': username, 'password': password, }; } } // 调用请求 final result = await postData(LoginRequest(username: 'demo', password: '123456'));
方案2:外部传入序列化函数(灵活性更高)
如果不想给所有实体类统一加接口约束,可以给方法新增一个序列化函数参数,由调用方传入具体的JSON转换逻辑,不需要约束泛型类型:
Future<ReturnModel> postData<T>(T model, Map<String, dynamic> Function(T instance) toJson) async { final response = await http.post( Uri.parse('https://localhost/SomeAddress'), headers: <String, String>{ 'Content-Type': 'application/json; charset=UTF-8', }, body: jsonEncode(toJson(model)) ); if (response.statusCode == StatusCode.OK) { return ReturnModel.fromJson(jsonDecode(response.body)); } else { throw Exception('请求发生错误'); } }
调用时手动传入对应实体的序列化逻辑即可:
final result = await postData<LoginRequest>( LoginRequest(username: 'demo', password: '123456'), (instance) => instance.toJson() );
这种方案不需要修改原有实体类的继承实现,适配第三方生成的实体类更方便,缺点是每次调用都需要传入转换函数,重复代码相对多一些。
实践建议
如果项目中网络请求场景较多,建议进一步封装网络请求基类,将基础域名、公共请求头、日志拦截、统一错误处理、响应解析等通用逻辑收拢,避免每次写请求都重复编写相同代码。后续如果使用json_serializable等自动化JSON序列化工具,上述两种方案都可以直接兼容,不需要修改核心请求逻辑。
内容的提问来源于stack exchange,提问作者Yargicx
相关产品推荐
相关产品推荐

