我有这段代码,我已经简化为下面的文件。
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
取决于ServiceA
以SampleModel
的形式获取数据。 但是我收到一个不应该发生的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);
});