在DART中创建泛型类型的示例

t3irkdon  于 2023-02-27  发布在  其他
关注(0)|答案(9)|浏览(179)

我想知道是否可以在Dart中创建泛型类型的示例。在其他语言中,如Java,您可以使用反射来解决这个问题,但我不确定这在Dart中是否可行。
我有这样的课:

class GenericController <T extends RequestHandler> {

    void processRequest() {
        T t = new T();  // ERROR
    }
}
t2a7ltrp

t2a7ltrp1#

我在Activator中尝试过mezonis方法,它很有效,但是它使用镜像,这是一种昂贵的方法,如果你不想有一个2 - 4MB的js文件,它需要你使用"mirrorsUsed"。
今天早上我想到了使用一个泛型typedef作为生成器,从而摆脱反射:
定义方法类型如下:(必要时添加参数)

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());

你不会失去使用泛型的优势,因为在声明的时候你无论如何都需要提供目标类,所以定义创建者方法并没有什么坏处。

x8diyxa7

x8diyxa72#

您可以使用类似的代码:

import "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'.");
    }
  }
}
qlfbtfca

qlfbtfca3#

我不知道这对任何人是否仍然有用,但是我发现了一个简单的解决方法,在你想要初始化类型T的函数中,传递一个额外的T Function()类型的参数,这个函数应该返回一个T的示例,现在无论何时你想要创建T的对象,调用这个函数。

class foo<T> {
    void foo(T Function() creator) {
        final t = creator();
        // use t
    }
}

附言:受Patrick's answer启发

wz3gfoph

wz3gfoph4#

2022回答

刚刚遇到这个问题,发现虽然使用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)

没有什么不同,但看起来更干净imo。

zpqajqem

zpqajqem5#

下面是我为这个可悲的限制所做的工作

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();
}
zfycwa2u

zfycwa2u6#

对不起,但是据我所知,在Dart中,类型参数不能用来命名示例创建表达式中的构造函数。

falq053o

falq053o7#

    • 使用Flutter**
typedef S ItemCreator<S>();

mixin SharedExtension<T> {

    T getSPData(ItemCreator<T> creator) async {
        return creator();
    }
}

Abc a = sharedObj.getSPData(()=> Abc());

附言:受Patrick启发

yhuiod9q

yhuiod9q8#

就这么简单。

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});
}
anauzrmj

anauzrmj9#

Patrick's answer的启发,这就是我最终拥有的工厂。

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(这样的话,确保类型名称的唯一性是消费者的责任),但这可能是唯一的方法。

相关问题