web-dev-qa-db-ja.com

DARTでジェネリック型のインスタンスを作成する

Dartでジェネリック型のインスタンスを作成できるかどうか疑問に思っていました。 Javaのような他の言語では、リフレクションを使用してこれを回避できますが、Dartでこれが可能かどうかはわかりません。

私はこのクラスを持っています:

class GenericController <T extends RequestHandler> {

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

同様のコードを使用できます。

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

私はアクティベーターでメゾニスアプローチを試してみましたが、うまくいきました。しかし、2-4MBのjsファイルが必要ない場合は "mirrorsUsed"を使用する必要があるミラーを使用するため、コストのかかるアプローチです。

今朝、私はジェネレーターとして一般的な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());

宣言時にターゲットクラスを提供する必要があるため、genericを使用する利点を失うことはありません。したがって、creatorメソッドを定義しても害はありません。

51

これがこの悲しい限界に対する私の回避策です

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

申し訳ありませんが、私の知る限り、Dartのインスタンス作成式では、型パラメーターを使用してコンストラクターに名前を付けることはできません。

1
yorodm