我想知道在Dart中是否可以创建泛型类型的实例。在其他语言中,比如Java,你可以使用反射来解决这个问题,但我不确定在Dart中是否可行。
我有这个类:
class GenericController <T extends RequestHandler> {
void processRequest() {
T t = new T(); // ERROR
}
}
我想知道在Dart中是否可以创建泛型类型的实例。在其他语言中,比如Java,你可以使用反射来解决这个问题,但我不确定在Dart中是否可行。
我有这个类:
class GenericController <T extends RequestHandler> {
void processRequest() {
T t = new T(); // ERROR
}
}
typedef S ItemCreator<S>();
或者更好的是:
typedef ItemCreator<S> = S Function();
接下来在需要创建新实例的类中:
class PagedListData<T>{
...
ItemCreator<T> creator;
PagedListData(ItemCreator<T> this.creator) {
}
void performMagic() {
T item = creator();
...
}
}
PagedList
:PagedListData<UserListItem> users
= new PagedListData<UserListItem>(()=> new UserListItem());
您使用泛型并不会失去优势,因为在声明时您需要提供目标类,因此定义创建者方法不会有任何影响。
creator()
如何创建T
的实例而不是ItemCreator<T>
的实例。你能为我解释一下吗? - tufekoiPagedListData
内部动态实例化类型会更好。但我认为在Flutter中没有镜像的情况下这是不可能的。 - DarkNeuronimport "dart:mirrors";
void main() {
var controller = new GenericController<Foo>();
controller.processRequest();
}
class GenericController<T extends RequestHandler> {
void processRequest() {
//T t = new T();
T t = Activator.createInstance(T);
t.tellAboutHimself();
}
}
class Foo extends RequestHandler {
void tellAboutHimself() {
print("Hello, I am 'Foo'");
}
}
abstract class RequestHandler {
void tellAboutHimself();
}
class Activator {
static createInstance(Type type, [Symbol constructor, List
arguments, Map<Symbol, dynamic> namedArguments]) {
if (type == null) {
throw new ArgumentError("type: $type");
}
if (constructor == null) {
constructor = const Symbol("");
}
if (arguments == null) {
arguments = const [];
}
var typeMirror = reflectType(type);
if (typeMirror is ClassMirror) {
return typeMirror.newInstance(constructor, arguments,
namedArguments).reflectee;
} else {
throw new ArgumentError("Cannot create the instance of the type '$type'.");
}
}
}
除了以下代码外,较新版本的Dart允许您在实例化时甚至不传递泛型类型,代码变得更加简洁:
final myClass = MyClass(SomeOtherClass.new);
T()
进行实例化仍然不可能,但是在 dart>=2.15
中可以更容易地获取对象的构造函数,使用 SomeClass.new
。class MyClass<T> {
final T Function() creator;
MyClass(this.creator);
T getGenericInstance() {
return creator();
}
}
final myClass = MyClass<SomeOtherClass>(SomeOtherClass.new)
.new
。 - Dinesh.new
但它并没有创建SomeOtherClass
的实例。除非我漏掉了什么。 - Dineshfinal myClass = MyClass(SomeOtherClass.new)
- Andrii Syrokomskyi我不知道这对任何人是否仍然有用。但是我找到了一个简单的解决方法。在你想要初始化类型T的函数中,传递一个额外的参数,类型为T Function()
。这个函数应该返回T的一个实例。现在每当你想要创建T对象时,调用这个函数即可。
class foo<T> {
void foo(T Function() creator) {
final t = creator();
// use t
}
}
P.S. 受到 Patrick的回答 的启发
class RequestHandler {
static final _constructors = {
RequestHandler: () => RequestHandler(),
RequestHandler2: () => RequestHandler2(),
};
static RequestHandler create(Type type) {
return _constructors[type]();
}
}
class RequestHandler2 extends RequestHandler {}
class GenericController<T extends RequestHandler> {
void processRequest() {
//T t = new T(); // ERROR
T t = RequestHandler.create(T);
}
}
test() {
final controller = GenericController<RequestHandler2>();
controller.processRequest();
}
使用Flutter开发
typedef S ItemCreator<S>();
mixin SharedExtension<T> {
T getSPData(ItemCreator<T> creator) async {
return creator();
}
}
Abc a = sharedObj.getSPData(()=> Abc());
顺便说一句,这篇文章的灵感来自Patrick
class ServiceFactory<T> {
static final Map<Type, dynamic> _cache = <String, dynamic>{};
static T getInstance<T>(T Function() creator) {
String typeName = T.toString();
return _cache.putIfAbsent(typeName, () => creator());
}
}
然后我会像这样使用它。
final authClient = ServiceFactory.getInstance<AuthenticationClient>(() => AuthenticationClient());
警告:Erik在下面的评论中指出,相同类型名称可能存在于多个包中,这将导致问题。尽管我不喜欢强制用户传递字符串key
(这样消费者负责确保类型名称的唯一性),但那可能是唯一的方法。
Map<Type, dynamic> _cache
和 _cache.putIfAbsent(T, () => creator());
。 - Erik Ernst就是这么简单。
import 'dart:mirrors';
void main(List<String> args) {
final a = A<B>();
final b1 = a.getInstance();
final b2 = a.getInstance();
print('${b1.value}|${b1.text}|${b1.hashCode}');
print('${b2.value}|${b2.text}|${b2.hashCode}');
}
class A<T extends B> {
static int count = 0;
T getInstance() {
return reflectClass(T).newInstance(
Symbol(''),
['Text ${++count}'],
{Symbol('value'): count},
).reflectee;
}
}
class B {
final int value;
final String text;
B(this.text, {required this.value});
}