abstract class Ainterface {
String? name;
List<Binterface?>? list;
}
abstract class Binterface {
String? age;
int? len;
}
class ObjA extends Ainterface {
String? name;
List<ObjB?>? list;
ObjA({this.name, this.list});
}
class ObjB extends Binterface {
String? age;
int? len;
ObjB({this.age, this.len});
}
我使用objb作为列表中每个项目的类型,但是编辑器给出了一个错误'obja '。List =' (') void function (List <objb吗?>?))不是对' interface '的有效覆盖。= '列表("void函数(List<Binterface祝辞?)")。>
我怎样才能解决这个问题?
Dart中的字段(数据成员)隐式地提供getter和setter作为接口的一部分。因此当你写:
abstract class Ainterface {
List<Binterface?>? list;
}
接口是隐式的:
abstract class Ainterface {
List<Binterface?>? get list;
set list(List<Binterface?>? value);
}
问题是你的派生类想要提供一个接口:
class ObjA extends Ainterface {
List<ObjB?>? get list;
set list(List<ObjB?>? value);
}
尽管List<ObjB?>?
可以替代List<Binterface?>?
,但反过来是不成立的:List<Binterface?>?
不能替代List<ObjB?>?
,这是setter重要的方向。
ObjA
中的list
setter不是Ainterface
中相应setter的安全重写,因为它将允许调用者违反其契约。Ainterface.list
声明它允许设置为任何Binterface
的实例,但ObjA.list
只期望ObjB
的实例。作为一个具体的例子,如果允许重写,那么下面的代码将没有错误地编译:
class AnotherB extends Binterface {}
void main() {
Ainterface a = ObjA();
a.list = [AnotherB()]; // This error would not be caught at compile-time.
}
现在a.list
包含一个List<AnotherB>
,即使ObjA.list
期望List<ObjB>
,如果你试图使用a.list
作为List<ObjB>
,你最终会在运行时得到一个错误。
如果您可以在逻辑上保证上述场景永远不会发生,那么您可以使用covariant
关键字来放松静态类型检查并允许重写:
abstract class Ainterface {
covariant List<Binterface?>? list;
}
,但我再次强调,上面的代码删除了一些类型安全。通过使用covariant
关键字,您有责任确保您在实践中不违反合同。
另外:
- 重新考虑你的抽象基类是否需要将setter作为其接口的一部分公开,如果可能的话只公开getter。
- 使
Ainterface
成为一个泛型类,参数化Binterface
的具体类型:abstract class Ainterface<DerivedB extends Binterface> { List<DerivedB?>? list; } class ObjA extends Ainterface<ObjB> { List<ObjB?>? list; }
我还会指出覆盖字段通常是一个坏主意,无论如何,您通常应该显式地覆盖getter和setter。
在Ainterface
抽象类中,您声明应该将列表声明为Binterface
类型,因此任何扩展该类的类都应该这样做。所以当你想要声明一个类来扩展这个类时,你应该考虑到这一点。如果你还想从ObjB类型声明一个列表,你可以在那之后做。它将像这样:
class ObjA extends Ainterface {
String? name;
List<Binterface?>? list;
List<ObjB ?>? list2;
ObjA({this.name, this.list, this.list2});
}