Ângelo Polotto
Ângelo Polotto

Reputation: 9511

Limit a generic type argument only to be a int, double or custom class

I trying make the following code but T only can be int, double or a custom class. I couldn't find how to restrict the type in Dart or something that work like where from C#. How can I do that in Dart?

class Array3dG<T> extends ListBase<T> {
  List<T> l = List<T>();
  Array3dG(List<T> list) {
    l = list;
  }
  set length(int newLength) { l.length = newLength; }
  int get length => l.length;
  T operator [](int index) => l[index];
  void operator []=(int index, T value) { l[index] = value; }
}

Upvotes: 2

Views: 1686

Answers (3)

Hpbbs
Hpbbs

Reputation: 1

if only for int and double, you can use num data type; then <T extends num> for custom class, you can sealed class Custom, then <T extends Custom>

Upvotes: 0

Mattia
Mattia

Reputation: 6524

You can check at runtime the type with the is keyword:

Array3dG(List<T> list) {
   if (list is List<int>) {
        //Handle int
   }
   else if (list is List<double>) {
        //Handle double
   }
   else if (list is List<MyClass>) {
        //Handle MyClass
   }
   else {
       throw ArgumentError('Unsupported $T type');
   }
  }

Note that if you are handling int and double in the same way you can just check for num

You can check the progress of the Union types here: https://github.com/dart-lang/sdk/issues/4938

Upvotes: 2

lrn
lrn

Reputation: 71623

There is no way to constrain the type variable at compile-time. You can only have one bound on a type variable, and the only bound satisfying both int and your custom class is Object.

As suggested by @Mattia, you can check at run-time and throw in the constructor if the type parameter is not one of the ones you supprt:

Array3dG(this.list) { 
  if (this is! Array3dG<int> && 
      this is! Array3dG<double> && 
      this is! Array3dG<MyClass>) {
    throw ArgumentError('Unsupported element type $T');
  }
}

This prevents creating an instance of something wrong, but doesn't catch it at compile-time.

Another option is to have factory methods instead of constructors:

class Array3dG<T> {
  List<T> list;
  Array3dG._(this.list);
  static Array3dG<int> fromInt(List<int> list) => Array3dG<int>._(list);      
  static Array3dG<int> fromDouble(List<double> list) => Array3dG<double>._(list);      
  static Array3dG<MyClass> fromMyClass(List<MyClass> list) => Array3dG<MyClass>._(list);
  ...
}

which you then use as Array3dG.fromInt(listOfInt). It looks like a named constructor, but it is just a static factory method (so no using new in front).

Upvotes: 4

Related Questions