Flutter 使用 T 扩展接口创建通用函数

Mik*_*ike 7 generic-programming function-templates dart flutter

语境

在我的代码中,我有一个名为的接口AbstactDataModel,用作所有数据模型类的起点。实现这一点是为了让我知道无论xyzModel我需要什么类,它都会有一个fromJson(Map<String, dynamic> json)函数,该函数将返回使用给定的 json 和type.

// In abstract_model.dart
abstract class AbstractDataModel {
  ///
  /// returns a String containing the class name
  /// For example, the class ColumnModel will return 'column'
  ///
  String get type;

  ///
  /// Will call the [.fromJson] constructor and return a new instance of the
  /// object
  ///
  dynamic fromJson(Map<String, dynamic> json);
}
Run Code Online (Sandbox Code Playgroud)

下面是一个扩展了 DataModel 类的示例AbstractDataModel

// in group_model.dart
class GroupModel extends AbstractDataModel {
  int _id;
  String _name;

  // Constructors
  GroupModel.empty();
  GroupModel.fromJson(Map<String, dynamic> json) {
    _id = parseToInt(json['id'].toString());
    _name = parseToString(json['name'].toString());
  }

  // Getters for private fields
  int get id => _id;
  String get name => _name;
  @override
  String get type => 'group';

  @override
  GroupModel fromJson(Map<String, dynamic> json) => GroupModel.fromJson(json);
}
Run Code Online (Sandbox Code Playgroud)

“损坏”的代码

我创建了一个函数,将 API 请求发送到服务器,然后将 json 响应解析为 DataModel 类型的对象。为了避免代码重复并使源代码更易于维护,我想创建一个通用函数,如下所示:

// inside the API class (which is a singleton)
Future<T> getObject<T extends AbstractDataModel>({
@required String command,
@required Map<String, dynamic> params,
}) async {
    final Response response = await _sendRequest(
        command: command,
        params: params,
    );
    T object;
    final Map<String, dynamic> body =
        jsonDecode(response.body)['result'] as Map<String, dynamic>;
    if (body == null) {
        print('Request failed.');
        throw const Failure('Failed request to fetch object.');
    } else {
        object = (T as AbstractDataModel).fromJson(body) as T;
        print('Successfully fetched ${object.type}');
        return object;
    }
}
Run Code Online (Sandbox Code Playgroud)

我期望使用它的方式如下:

GroupModel group = await API().getObject<GroupModel>();
Run Code Online (Sandbox Code Playgroud)

预期行为

我希望该getObject函数知道,因为Textends AbstractDataModel,所以该fromJson(...)函数存在,并使用它来创建一个新GroupModel对象,同时只接受扩展的对象AbstractDataModel,即抛出一个错误,getObject<int>()比如“int 不扩展 AbstractDataModel”。

实际行为

在执行过程中,我收到一个未处理的错误,表明类型 _Type 不是 的子类型AbstractDataModel,因此强制转换(T as AbstractDataModel)无效。

另外,设置断点并通过调试器检查一些值,我测试了以下语句:

T is AbstractDataModel: false
T is GroupModel: true
T is AnyOtherDataModelThatExtendsAbstractDataModel: true
Run Code Online (Sandbox Code Playgroud)

所以我什至无法通过switch语句来处理它,因为即使我调用getObject<GroupModel>(),该语句T is ProjectModel仍然被评估为 true。关于我做错了什么的任何指示吗?

小智 0

您可以使用此包以便在通用类Json_Mapper中使用 fromJson

JsonMapper.register(JsonObjectMapper(
  (CustomJsonMapper mapper, Map<String, dynamic> json) =>
      Model.fromJson(json),
  (CustomJsonMapper mapper, Model instance) => <String, dynamic>{},
));
Run Code Online (Sandbox Code Playgroud)

然后在你的通用类中

T t = JsonMapper.deserializeFromMap<T>(json)!
Run Code Online (Sandbox Code Playgroud)