Dart:具有 .fromJson 构造函数的泛型

问题描述 投票:0回答:4

在 Swift 中,我习惯于设置一个

protocol JSONInitializable
,它定义了一个
init?(json: JSON)
,这意味着所有符合协议的类和结构都可以使用 JSON 对象进行初始化。

这在 Dart 中是否不可能(带有

abstract class
),因为静态方法和工厂初始化器不是从抽象类继承的?

我问的原因是因为我正在为 API GET 请求编写很多类似的方法,这些方法可以很容易地合并为一个,例如:

static Future<T> get<T extends JSONInitializable>(int id) async {
  final resourceName = T; // TODO: transform to snake case
  final uri = Uri.parse("$kApiHostname/api/$resourceName/$id");

  final response = await _secureGet(uri);
  if (response == null) {
    return null;
  }

  final responseJson = json.decode(response.body);
  final model = T.fromJson(responseJson);

  return model;
}

但要使其工作,我需要将

T
限制为定义
.fromJson()
初始值设定项的协议/接口。

json generics dart
4个回答
1
投票

您想要的功能在 Dart 中不可用(或计划中),但已经有过讨论。

给这个问题点赞:https://github.com/dart-lang/language/issues/356


0
投票

手动解决方法可能是拥有序列化器、反序列化器的映射,例如:

//Register object 1 in singleton
  JsonMapper.register<MyObject>(JsonObjectMapper(
    (mapper, map) => MyObject.fromJson(map),
    (mapper, instance) => instance.toJson(),
  ));
//Register object 2 in singleton...
...

通过这种方式,只要您注册了对象,就可以反序列化和序列化对象,而无需诉诸其泛型类型。

自动(技术上代码生成)方式将使用像 simple_json 这样的包来帮助您通过少量代码生成来解决此问题,这样您就不会搞砸注册和消除映射器。

最大的优点是,将对象从 JSON 转换为 JSON 的实际代码并不存储在对象本身中,而是存储在生成的类中,从而将序列化反序列化的责任从对象推到生成的代码中(以解耦的方式) ).

请对我的建议持保留态度,因为这两种方法都会丢失静态类型检查,检查类型是否具有已注册的映射器并且可以转换。


0
投票

这个答案可能会有所帮助。您只需将 fromJson 构造函数作为参数传递即可。

我遵循的简单步骤

  1. 创建一个抽象类

    抽象类BaseModel{ 工厂 BaseModel.fromJson(Map json) { 抛出未实现的错误(); } 地图? toJson(); }

  2. 实现基类

    @JsonSerialized() 类 ServerStatus 实现 BaseModel { ServerStatus(this.status, this.message); 字符串状态=''; 字符串消息 = '';

    @覆盖 工厂 ServerStatus.fromJson(Map json) => _$ServerStatusFromJson(json);

    @覆盖 地图? toJson() => _$ServerStatusToJson(this); }

  3. 在您尝试访问 fromJson 方法的逻辑类中

    类 CustomHttp { CustomHttp(this.构造函数); T Function(Map) 构造函数; Future get(String path) 异步 { 最终响应=等待http.get(this.uri); 最终 Map 解析 = json.decode(response.Body); 返回构造函数(已解析); } }


0
投票

不幸的是,Dart 不支持实现此目标的一些非常重要的功能:从泛型参数调用静态方法。例如。在 C++ 模板(虽然不是泛型)中,您可以编写如下代码:

template<typename T>
T deserialize(MyStream istrm) { return T.deserialize(istrm); }

但是正如之前的答案中提到的,我们不能在 dart 中做同样的事情。

解决方案

目前在我的解决方案中我使用反射。

尽管 dart 有内置的 mirrors,但是(突然)flutter 不支持它。因此我们被要求在 flutter 中使用 reflectable 包。你能感觉到吗?当我们试图解决一个问题时,却遇到了另一个问题。尽管如此。

使用反射,您可以扫描模块中具有特定注释(例如

@my_deserializable
)的类,然后收集静态方法。请注意,您可以编写自己的注释。

因此你可以建立一个工厂缓存,就像

Map<Type, Function(MyStream istrm)> deserializers
一样。因此,拥有这样的工厂,您就可以按如下方式使用它:

deserializers[T]!(responseJson);
© www.soinside.com 2019 - 2024. All rights reserved.