我有一个模型,我希望从HTTP请求中获取响应并将其映射.问题是这个模型有一个可以接受任何属性的属性,但我想正确地映射它.

class BaseResponse<T> {
  final bool error;
  final String? message;
  final T? result;

  const BaseResponse({required this.error, this.message, this.result});

  factory BaseResponse.fromJson(Map<String, dynamic> json) {
    bool error = json['error'];
    String? message = json['message'];
    T? result = json['result'];

    return BaseResponse(error: error, message: message, result: result);
  }
}

我想找出一种方法,可以将JSON中的正确数据映射到Result属性中.结果属性可以是复杂的模型,也可以是像String这样的简单属性.

class SampleModel {
    final String firstName;
    final String lastName;
    final AddressModel address;

    SampleModel({ required this.firstName, required this.lastName, required this.address });
}

class AddressModel {
    final String street;
    final String city;
    // ... more properties

    AddressModel({ required this.street, required this.city, /* More properties here */ });
}

void main() {
    Future<void> getResponse() async {
        Future<http.Response> response = await http.get('https://getsomething.com');

        // Do some checks against response

        BaseResponse<SampleModel> = BaseResponse.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
    }

    getResponse();
}

推荐答案

如果你知道你想要一个BaseResponse<SampleModel>,并且你需要为SampleModel做一些特定的事情,那么你必须调用知道该做什么的代码,或者告诉代码该做什么.

我要做的是向SampleModel.fromJson添加一个将json[result]转换为所需类型的函数参数,然后将所需结果类型的解码器传递给它:

  factory BaseResponse.fromJson(Map<String, dynamic> json, 
      T? Function(Object?) parseResult) {
    bool error = json['error'];
    String? message = json['message'];
    T? result = parseResult(json['result']);
    return BaseResponse(error: error, message: message, result: result);
  }

SampleModel声明一个解码器:

static SampleModel fromJson(Object? result) {
  if (result case {
      "firstName": String first,  
      "lastName": String last,
      "address": Map<String, Object?> addressJson,
      // ..
    }) {
      var address = AddressModel.fromJson(addressJson);
      if (address != null) {
        return SampleModel(firstName: first, lastName: last, address: address);
      }
    }
    return null;
  }

并在调用fromJson时传递该函数:

      // Do some checks against response
      BaseResponse<SampleModel> model = BaseResponse.fromJson(
          jsonDecode(response.body) as Map<String, dynamic>,
          SampleModel.fromJson); // <-- added here.

BaseResponse是由一个类型进行参数化的.在BaseResponse类中,泛型类型参数应该被视为generically.也就是说,如果代码不应该依赖于实际绑定到T的类型,它应该对任何类型都相同.

这确实意味着任何type-specific行为都必须从BaseResponse类之外提供. DART不允许通过类型参数调用静态函数, 因此,需要 for each 实际类型参数提供不同行为的任何功能都需要传递到类中.在需要时或在构造函数中.

另一种削减抽象的方式可以是传入结果value, 并从另一个助手函数调用BaseResponse.fromJson:

class BaseResponse<T extends Object> {
  ...
  BaseResponse.fromJson(Map<String, dynamic> json, T? result) :
    this(error: json['error'], message: json['message'], result: result);
}

class SampleModel {
  static SampleModel? fromJson(Map<String, dynamic> json) {
    // Parse firstName/lastName/etc as above.
    return sample;
  }

  static BaseResponse<SampleModel> baseFromJson(Map<String, dynamic> json) {
    SampleModel? result = fromJson(json);
    return BaseResponse<SampleModel>(json, result);
  }
}

然后,这将由如下代码调用:

  // Do some checks against response.
  BaseResponse<SampleModel> model = SampleModel.baseFromJson(json);

这还 Select 了一条代码路径,该代码路径为判断所说要使用的SampleModel做一些特定的事情,并使用泛型 代码BaseResponse,其输入取决于泛型类型. 它只是传递一个值,而不是用来创建值的函数.

这两种方法都不管用.

Dart相关问答推荐

使用arm64v8/DART Docker映像进行编译时不支持DART镜像

ListView 不会刷新,而附加列表会刷新 (Flutter)

如何在 Flutter 上实现事件监听器或委托

如何将指针事件发送到堆栈中的低级子级

在 Dart 中,List.unmodifiable() 和 UnmodifiableListView 有什么不同?

Flutter 扩展方法不起作用,它说undefined class和requires the extension-methods language feature

在 Flutter 中将图像与左上角对齐

不要将 PageView 居中 - Flutter

Flutter 错误:The _ScaffoldLayout custom multichild layout delegate forgot to lay out the following child

Expansion Panel底部溢出

使用Flatter向Cloud Firestore添加对象

如何减少 ListView.builder 中 RaisedButton 的宽度?

无法使用 Flutter 调用 Localhost,将随机端口分配给 HTTP GET 调用

使用 dart 下载文件

如何使用工厂构造函数扩展抽象类?

polymer SEO 是否友好?

Dart MD5 字符串

如何在 Dart 中逐个字符地迭代字符串?

如何初始化构造函数主体中的最终字段?

如何停止 Dart 的 .forEach()?