首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用泛型将List<SuperType>转换为List<SubType>

使用泛型将List<SuperType>转换为List<SubType>
EN

Stack Overflow用户
提问于 2020-02-29 03:46:22
回答 1查看 3.2K关注 0票数 3

我是新来的颤栗和飞镖,来自本土Android。

Android有一个非常好的数据库抽象体系结构,称为Room Persistence Library。据我所知,使用MVVM / MVC设计模式并不存在这样的数据库抽象体系结构。

我的解决方案是自己创建一个Dart版本。在经历了几次头痛之后,我做了很多事情,但我似乎无法让LiveData使用泛型来正常工作。

我这样安排我的课:

代码语言:javascript
复制
class LiveData<T> {
  ...
}

现在,当我想返回一些数据时,可以是ObjectList<Object>。我发现了一个巧妙的方法来区分两者和T

代码语言:javascript
复制
...

// Parse response
// This checks if the type is an instance of a single entity or a list.
if (entity is T) {
  cachedData = rawData.isEmpty ? null : entity.fromMap(rawData.first) as T;
} else {
  cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
}

...

问题在于第二块:

代码语言:javascript
复制
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;

有错误:

代码语言:javascript
复制
 - Unhandled Exception: type 'List<Entity>' is not a subtype of type 'List<Vehicle>' in type cast

然后,问题就变成了:当我没有访问Entity类的权限时,如何将Vehicle转换为Vehicle。它的一个实例只分配给一个Entity entity变量。

下面是演示我访问Vehicle的一个片段

代码语言:javascript
复制
final Entity entity;

...assign Vehicle instance to entity...

print(entity is Vehicle)  // True

我试过使用.runtimeType,但没有效果。我还考虑过将LiveData分成两个类,第二个类是LiveDataList。虽然这似乎是最简单的解决方案,不错误的代码-它将困扰我(坏双关是故意的),并打破否则相当直接的端口的房间。

作为一种临时解决方案,我将构建逻辑抽象为一个泛型函数,以传递给构造函数中的LiveData

代码语言:javascript
复制
final T Function(List<Map<String, dynamic>> rawData) builder;

现在,我将其称为构建cachedData的前面的代码。

代码语言:javascript
复制
// Parse response
cachedData = builder(rawData);

在访问LiveData<List<Vehicle>>中的所有车辆时调用Dao<Vehicle>的构造函数为:

代码语言:javascript
复制
class VehicleDao implements Dao<Vehicle> {
  ...

  static LiveData<List<Vehicle>> get() {
    return LiveData<List<Vehicle>>(
      ...
      (rawData) => rawData.map((e) => Vehicle.fromMap(e)).toList(),
      ...
    );
  }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-02-29 04:08:12

在Dart中(实际上在许多语言中),泛型都有继承的概念。您可能会认为,如果Bar是从Foo继承的,那么List<Bar>也可以传递给List<Foo>

实际上,由于泛型的工作方式,情况不会如此。当您有一个泛型类时,每次使用该类具有不同类型时,该类型都被视为一个完全独立的类。这是因为当编译器编译这些类型时,class MyGenericType<Foo> extends BaseClassclass MyGenericType<Bar> extends BaseClass基本上被转换为class MyGenericType_Foo extends BaseClassclass MyGenericType_Bar extends BaseClass

你看到问题了吗?MyGenericType_FooMyGenericType_Bar不是彼此的后代。他们是彼此的兄弟姐妹,都是从BaseClass延伸出来的。这就是为什么当您尝试将List<Entity>转换为List<Vehicle>时,转换不能工作,因为它们是同级类型,而不是超级类型和子类型。

尽管不能根据泛型类型参数的关系直接将一个泛型类型转换为另一个泛型类型,但在List的情况下,有一种方法可以将一种List类型转换为另一种类型:cast方法。

代码语言:javascript
复制
List<Entity> entityList = <Entity>[...];
List<Vehicle> vehicleList = entityList.cast<Vehicle>(); // This cast will work

但是要注意的一点是,如果您要从超级泛型转换为子类型泛型,并且列表中的所有元素都是新类型,则此强制转换将引发一个错误。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60461815

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档