Создание экземпляра родового типа в DART

Мне было интересно, возможно ли создать экземпляр родового типа в Dart. На других языках, таких как Java, вы можете обойти это с помощью отражения, но я не уверен, возможно ли это в Dart.

У меня есть этот класс:

class GenericController <T extends RequestHandler> {

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

Ответ 1

Вы можете использовать похожий код:

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

Ответ 2

Я попытался использовать mezonis с Activator, и он работает. Но это дорогостоящий подход, поскольку он использует зеркала, что требует от вас использования "mirrorUsed", если вы не хотите иметь файл js 2-4MB.

Сегодня утром у меня возникла идея использовать общий генератор typedef в качестве генератора и, таким образом, избавиться от отражения:

Вы определяете тип метода следующим образом: (При необходимости добавьте параметры)

typedef S ItemCreator<S>();

Затем в классе, который должен создать новые экземпляры:

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

Вы не теряете преимущества использования общего, потому что во время объявления вам нужно предоставить целевой класс, так что определение метода создателя не повредит.

Ответ 3

Извините, но насколько я знаю, параметр типа нельзя использовать для обозначения конструктора в выражении создания экземпляра в Dart.

Ответ 4

Вот моя работа для этого печального ограничения

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