我是Flutter和Dart的新手,来自本地Android。
Android有一个非常好的数据库抽象架构,称为Room Persistence Library。据我所知,使用MVVM / MVC设计模式的Flutter没有这样的数据库抽象体系结构。
我的解决方案是自己创建Dart版本。经过几次头痛之后,我几乎完成了所有工作,但似乎无法使LiveData
使用泛型正常工作。
我像这样设置类(class):
class LiveData<T> {
...
}
现在,当我想返回一些数据时,它可以是
Object
或List<Object>
。我发现了一个巧妙的技巧,可以区分T
和两者:...
// 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;
}
...
问题出在第二块:
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
与错误:
- Unhandled Exception: type 'List<Entity>' is not a subtype of type 'List<Vehicle>' in type cast
问题就变成了:当我无权访问
Entity
类时,如何将Vehicle
转换为Vehicle
。仅将其实例分配给Entity entity
变量。这是一个片段,以演示我对
Vehicle
的访问:final Entity entity;
...assign Vehicle instance to entity...
print(entity is Vehicle) // True
我尝试使用
.runtimeType
无济于事。我还考虑过将LiveData
分为两个类,第二个是LiveDataList
。尽管这似乎是不对代码进行错误检查的最简单解决方案,但它可能会打扰我(故意是双关语)并破坏原本非常漂亮的Room端口。作为一个临时解决方案,我将构建逻辑抽象为一个通用函数,该函数将传递给构造函数中的
LiveData
。final T Function(List<Map<String, dynamic>> rawData) builder;
现在,我将其命名为
cachedData
,而不是之前的代码。// Parse response
cachedData = builder(rawData);
访问
LiveData<List<Vehicle>>
中的所有车辆时,调用Dao<Vehicle>
的构造函数是:class VehicleDao implements Dao<Vehicle> {
...
static LiveData<List<Vehicle>> get() {
return LiveData<List<Vehicle>>(
...
(rawData) => rawData.map((e) => Vehicle.fromMap(e)).toList(),
...
);
}
}
最佳答案
在Dart中(实际上在许多语言中),泛型都带有继承的概念。您会认为,如果Bar
继承自Foo
,那么该List<Bar>
也将可转换为List<Foo>
。
实际上,由于泛型的工作原理,情况并非如此。当您有通用类时,每次您使用具有不同类型的该类时,该类型都被视为完全独立的类。这是因为当编译器编译这些类型时,class MyGenericType<Foo> extends BaseClass
和class MyGenericType<Bar> extends BaseClass
基本上会转换为class MyGenericType_Foo extends BaseClass
和class MyGenericType_Bar extends BaseClass
之类的东西。
看到问题了吗? MyGenericType_Foo
和MyGenericType_Bar
不是彼此的后代。他们是彼此的 sibling ,都从BaseClass
扩展。这就是为什么当您尝试将List<Entity>
转换为List<Vehicle>
时,强制转换不起作用的原因,因为它们是同级类型,而不是父类(super class)型和子类型。
综上所述,虽然不能基于通用类型参数的关系将一种通用类型直接转换为另一种通用类型,但是对于List
,有一种方法可以将一种List
类型转换为另一种类型:cast
方法。
List<Entity> entityList = <Entity>[...];
List<Vehicle> vehicleList = entityList.cast<Vehicle>(); // This cast will work
但是要注意的一件事是,如果您是从父类(super class)型泛型转换为子类型泛型,并且列表中的所有元素都不都是该新类型,则此转换将引发错误。
关于sqlite - Dart-使用泛型将List <SuperType>转换为List <SubType>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60461815/