泛型类型在dart中被继承覆盖

dtcbnfnu  于 2023-05-11  发布在  其他
关注(0)|答案(1)|浏览(198)

我创建了一个包含泛型数据类型的类。

class Buck<E> {
  List<E> list;
  Buck({
    required this.list,
  });
}

然后,我创建了一个类和一个子类:

class SomeThing {}
class SomethingOther extends SomeThing {}

我创建了一个对象Buck,其中ESomeThing类。

var buck = Buck<SomeThing>(list: List<SomeThing>.empty());

在这里,我假设buck.list的类型是List<SomeThing>。然后,我用List<SomethingOther>分配它。

buck.list = List<SomethingOther>.empty();

在这一点上,没有什么不寻常的。我假设buck.list的类型仍然是List<SomeThing>。但是,当我尝试将SomeThing对象添加到buck.list时,我得到一个错误:

buck.list.add(SomeThing()); // this will be error

下面是完整的代码:

void main() {
  var buck = Buck<SomeThing>(list: List<SomeThing>.empty());
  buck.list = List<SomethingOther>.empty();
  buck.list.add(SomeThing());
}

class Buck<E> {
  List<E> list;
  Buck({
    required this.list,
  });
}

class SomeThing {}
class SomethingOther extends SomeThing {}

为什么会出现这种情况?这是预期的行为吗?

kqhtkvqz

kqhtkvqz1#

如果DerivedBase的子类型,则Dart将Generic<Derived>视为Generic<Base>的子类型。因此,Generic<Derived>可分配给Generic<Base>
对于大多数泛型来说,这不是问题,而且它通常提供了方便。对于集合,它可能会导致您遇到的问题。List<Derived>只能存储 * Derived个元素。因此,如果代码试图添加其他Base元素,则将List<Derived>分配给List<Base>实际上并不安全。
真不幸
为了避免这种情况,您应该确保构造List<Something>,即使它是用SomethingOther元素初始化的。例如:

var list = <Something>[SomethingOther(), SomethingOther()];
var buck = Buck(list: list);

为了更好的保护,你可以让Buck创建自己的输入List的内部副本,这样它就可以确保它总是有一个List<Something>而不是List<SomethingOther>

class Buck<E> {
  List<E> _list = <E>[];

  List<E> get list => _list;

  set list(List<E> newList) {
    _list.clear();
    _list.addAll(newList);
  }

  Buck({required List<E> list}) {
    this.list = list;
  }
}

另见:

相关问题