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

shu*_*uen 21 dart

我想知道是否可以在Dart中创建泛型类型的实例.在像Java这样的其他语言中你可以使用反射来解决这个问题,但是我不确定这在Dart中是否可行.

我有这门课:

class GenericController <T extends RequestHandler> {

    void processRequest() {
        T t = new T();  // ERROR
    }
}
Run Code Online (Sandbox Code Playgroud)

Pat*_*sen 43

我尝试了使用Activator的mezonis方法,它的工作原理.但这是一种昂贵的方法,因为它使用镜像,如果你不想拥有2-4MB的js文件,则需要你使用"mirrorsUsed".

今天早上我有了使用泛型typedef作为生成器的想法,从而摆脱了反射:

您可以像这样定义一个方法类型:(如果需要,添加参数)

typedef S ItemCreator<S>();
Run Code Online (Sandbox Code Playgroud)

然后在需要创建新实例的类中:

class PagedListData<T>{
  ...
  ItemCreator<T> creator;
  PagedListData(ItemCreator<T> this.creator) {

  }

  void performMagic() {
      T item = creator();
      ... 
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你就可以像这样实现PagedList:

PagedListData<UserListItem> users 
         = new PagedListData<UserListItem>(()=> new UserListItem());
Run Code Online (Sandbox Code Playgroud)

您没有放弃使用泛型的优势,因为在声明时您无论如何都需要提供目标类,因此定义创建者方法不会受到伤害.

  • 与颤动一起工作 (5认同)
  • ItemCreator&lt;T&gt; 是返回 T 类型的函数的函数类型,如您在 typedef 中看到的。在最后一个代码片段中,您可以看到创建了 PagedListData 实例并提供了创建者函数的实例。这只是一个模板,而不是函数调用。该函数仅在中间代码片段的“creator()”处被调用。这有帮助吗? (2认同)
  • 这里真的没有魔法。它归结为通过回调将实例化责任委托给消费者。这不是一个糟糕的解决方案,但如果能够在没有它的情况下在 `PagedListData` 中动态实例化一个类型会很好。但我认为没有镜子是不可能的,而我们在 Flutter 中没有。 (2认同)

All*_* Hu 15

2023答案

除了以下代码之外,较新版本的 dart 允许您甚至无需传递泛型类型即可实例化,并且代码变得更加简洁:

final myClass = MyClass(SomeOtherClass.new);
Run Code Online (Sandbox Code Playgroud)

感谢@AndriiSyrokomskyi 指出了这一点。

2022年答案

刚刚遇到这个问题,发现虽然T()仍然无法实例化 using ,但可以使用SomeClass.newin更轻松地获取对象的构造函数dart>=2.15

所以你可以做的是:

class MyClass<T> {
  final T Function() creator;
  MyClass(this.creator);

  T getGenericInstance() {
    return creator();
  }
}
Run Code Online (Sandbox Code Playgroud)

使用时:

final myClass = MyClass<SomeOtherClass>(SomeOtherClass.new)
Run Code Online (Sandbox Code Playgroud)

没什么不同,但在我看来看起来更干净。


mez*_*oni 12

您可以使用类似的代码:

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'.");
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 还不能与颤振一起工作。+1 表示 Patrik 在下面的方法。 (7认同)

Hem*_*mil 8

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

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

Run Code Online (Sandbox Code Playgroud)

PS灵感来自帕特里克的回答


Ant*_*nko 7

这是我解决这个可悲限制的工作

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();
}
Run Code Online (Sandbox Code Playgroud)