为什么我的 sub class that implements/extends a parent class 在 Dart Flutter 中不被识别为父 class 的子类型?

Why isn't my sub class that implements/extends a parent class recognized as a sub type of the parent class in Dart Flutter?

我有实现 IIdentified class 的 ProjectModel class。但是在运行时,我得到一个错误,指出 ProjectModel 不是 IIdentified 的子类型,尽管它实现了它。我也曾尝试在 ProjectModel 中使用 extend 而不是 implements 但这也无济于事。我如何在 Dart Flutter 中使用接口,以便 Widget 可以具有满足特定接口或契约的通用类型?

Parent class IIdentified 我像接口一样使用:

abstract class IIdentified {
  String id;
  String name;
}

子 class 实现(也尝试扩展)父 class IIdentified:


class ProjectModel implements IIdentified {
  String id;
  DateTime created;
  DateTime updated;
  bool hasMileage;
  bool hasAllowance;
  bool hasTravelTime;
  String name;
  String description;
  DateTime startDate;
  DateTime endDate;
  DateTime completed;
  double estimatedTime;
  double absentTime;
  double presentTime;
  Status status;
  String companyId;
  String customerId;

  ProjectModel(
      {this.id,
      this.created,
      this.updated,
      this.hasMileage,
      this.hasAllowance,
      this.hasTravelTime,
      this.name,
      this.description,
      this.startDate,
      this.endDate,
      this.completed,
      this.estimatedTime,
      this.absentTime,
      this.presentTime,
      this.status,
      this.companyId,
      this.customerId});

我收到以下错误消息,我尝试传递的函数中的 ProjectModel 参数不算作 IIdentified:

The following _TypeError was thrown building LoaderDropdownButton<ProjectModel>(dirty, dependencies: [MediaQuery], state: LoaderDropdownButtonState<IIdentified>#f2031):
type '(ProjectModel) => void' is not a subtype of type '(IIdentified) => void'

通用小部件只接受类型 T extends IIdentified:

class LoaderDropdownButtonState<T extends IIdentified> extends State<LoaderDropdownButton<T>> {
  double displayWidth;
  double displayHeight;

  @override
  void initState() {
    init();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    setDisplayDimensions();
    return Container(
      padding: EdgeInsets.only(left: 25),
      color: widget.enableSelect ? themeConfig.dropButtonBg : themeConfig.dropButtonDisabledBg,
      child: Theme(
        data: ThemeData(canvasColor: Color(0xFFC5C5C5)),
        child: DropdownButtonHideUnderline(
          child: new DropdownButton<T>(
              hint: Row(
                children: <Widget>[
                  Expanded(
                    flex: 10,
                    child: Container(
                      alignment: Alignment.center,
                      margin: EdgeInsets.only(top: 2),
                      child: Text(
                        widget.text,
                        overflow: TextOverflow.ellipsis,
                        style: TextStyle(
                          color: widget.enableSelect
                              ? themeConfig.dropButtonFg
                              : themeConfig.dropButtonDisabledFg,
                          fontSize: displayWidth * 0.045,
                        ),
                      ),
                    ),
                  ),
                  Flexible(
                    flex: 2,
                    child: Container(
                      margin: EdgeInsets.only(top: 5),
                      child: Icon(
                        Icons.keyboard_arrow_down,
                        color: widget.enableSelect
                            ? themeConfig.dropButtonFg
                            : themeConfig.dropButtonDisabledFg,
                      ),
                    ),
                  )
                ],
              ),
              iconSize: 0,
              isExpanded: true,
              items: buildItems(),
              onChanged: widget.onChange),
        ),
      ),
    );
  }

  void init() {
    displayWidth = 1;
    displayHeight = 1;
  }

  setDisplayDimensions() {
    if (displayWidth == 1) displayWidth = MediaQuery.of(context).size.width;
    if (displayHeight == 1) displayHeight = MediaQuery.of(context).size.height;
  }

  List<DropdownMenuItem<T>> buildItems() {
    return widget.data.map((dataItem) {
      return DropdownMenuItem<T>(
        value: dataItem,
        child: Text(dataItem.name),
      );
    }).toList();
  }
}

为什么 ProjectModel 在 implements/extends 时不作为 IIdentified 通过?您如何在通用小部件中使用 interfaces/contracts?

谢谢!

I get the following error that the ProjectModel parameter in a function I'm trying to pass, does not count as being an IIdentified.

我不认为你真的粘贴了那个函数,但我仍然可以正确地猜到发生了什么。问题是您创建了一个带有签名的函数:

(ProjectModel) => void

并想将它用作需要 (IIdentified) => void 的参数。当我们谈论继承和方法参数时,这是一个常见的问题,因为它看起来有点落后。

但是,问题是如果你有一个可以接受 IIdentified 作为参数的方法,它应该能够接受所有类型的 IIdentified 而不仅仅是特定类型的 IIdentified。你不能只给出一个可以处理 ProjectModel 的函数并假设它能够处理 IIdentified.

的其他一些子类

如果我们改为将具有以下内容:

() => ProjectModel

那么这将是 () => IIdentified 的有效子类型,因为我们被允许 return 更具体的 IIdentified