Dart 无法推断子类的类型



我有这段代码,我已经简化为下面的文件。

import 'package:hooks_riverpod/hooks_riverpod.dart';
// this class disctates what other classes do
abstract class BaseUtils<T> {
T fromMap(Map<String, dynamic> json);
}
// Model to be used
class SampleModel extends BaseUtils {
late int? id;
SampleModel({
this.id,
});
@override
SampleModel fromMap(Map<String, dynamic> json) {
return SampleModel(
id: json['id'],
);
}
}
// First service
class ServiceA<T extends BaseUtils> {}
final serviceAProvider = Provider<ServiceA>((ref) {
return ServiceA();
});
class ServiceB {
final ServiceA<SampleModel> _service;
ServiceB(this._service);
void func() {
print(_service);
}
}
final serviceBProvider = Provider<ServiceB>((ref) {
final _a = ref.read(serviceAProvider);
//// Error here
return ServiceB(_a);
});

ServiceB取决于ServiceASampleModel的形式获取数据。 但是我收到一个不应该发生的IDE错误The argument type 'ServiceA<BaseUtils<dynamic>>' can't be assigned to the parameter type 'ServiceA<SampleModel>'

我可能做错了什么?

由于ServiceA是一个泛型类,因此当您编写Provider<ServiceA>而不为ServiceA指定类型参数时,Dart 会隐式使用满足其类型约束的最广泛的类型。 对于ServiceA<T>,因为T必须扩展BaseUtils,没有显式类型参数的ServiceA等价于ServiceA<BaseUtils>,而则等价于ServiceA<BaseUtils<dynamic>>,因为BaseUtils是一个泛型类,对其类型参数没有约束。

错误消息正确:您无法安全地将ServiceA<BaseUtils<dynamic>>分配给ServiceA<SampleModel>。 您有一个超类型 (ServiceA<BaseUtils<dynamic>>) 和一个子类型 (ServiceA<SampleModel>)。 虽然子类型是超类型,但并非每个超类型都是子类型!

analysis_options.yaml中启用strict-raw-types选项应该有助于将来发现类似的错误。

我对package:provider没有经验,但我希望解决方法是为您的泛型类提供显式类型。 例如:

final serviceAProvider = Provider<ServiceA>((ref) {
return ServiceA();
})

也许应该是:

final serviceAProvider = Provider<ServiceA<SampleModel>>((ref) {
return ServiceA<SampleModel>();
})

由于这需要为每个类型提供一个单独的serviceAProvider变量,因此创建一个泛型函数可能会更干净,以便调用方可以指定类型参数:

final _serviceAMap = <Type, Provider<ServiceA>>{};
Provider<ServiceA<T>> getServiceAProvider<T extends BaseUtils>() {
var provider = _serviceAMap[T];
if (provider != null) {
return provider as Provider<ServiceA<T>>;
}

return _serviceAMap[T] = Provider<ServiceA<T>>((ref) => ServiceA<T>());
}
final serviceBProvider = Provider<ServiceB>((ref) {
final _a = ref.read(getServiceAProvider<SampleModel>());
return ServiceB(_a);
});

最新更新