Flutter:类型<>不是<> ...的子类型,但它是

时间:2019-08-21 21:13:11

标签: inheritance flutter dart casting

免责声明::我知道有几个类似的问题,但是没有一个问题可以帮助我了解此特定情况下的问题。


我创建了一个接受ChangeNotifier的实用程序小部件,并在数据更改时自动重建该小部件。

此小部件的代码略有缩短,但是可见的问题却是可见的:

class ChangeNotifierConsumer<T extends ChangeNotifier> extends StatefulWidget {
  const ChangeNotifierConsumer({
    Key key,
    @required this.notifier,
    @required this.builder,
  }) : super(key: key);

  final T notifier;

  final Widget Function(BuildContext context, T cache) builder;

  @override
  _ChangeNotifierConsumerState createState() => _ChangeNotifierConsumerState();
}

class _ChangeNotifierConsumerState extends State<ChangeNotifierConsumer> {
  @override
  Widget build(BuildContext context) => widget.builder(context, widget.notifier);
}
class Model extends ChangeNotifier { ... }

然后我将按以下方式使用小部件,但这就是发生错误的地方:

ChangeNotifierConsumer<Model>(
    notifier: Model(),
    builder: (BuildContext context, Model model) { ... }
)

确切的错误消息是:

type '(BuildContext, Model) => ListView' is not a subtype of type '(BuildContext, ChangeNotifier) => Widget'

dart分析也没有编译时错误或输出,仅在运行时失败。

尽管模型扩展了ChangeNotifier,为什么仍会发生此错误?

如果我按以下方式使用构建器,则没有问题:

    builder: (BuildContext context, dynamic model) { 
       Model model = model as Model;    
    }

1 个答案:

答案 0 :(得分:0)

Imho在扩展ChangeNotifier的方法中存在一个小错误。

在OOP中扩展表示“是”。 例如,狮子扩展动物=>狮子是动物。

在您的情况下,通过扩展ChangeNotifier,您基本上可以说:

模型是一个ChangeNotifier,不是这种情况。如果我错了请纠正我。

我很想弄清楚类型问题,但不知道为什么会这样。 同时,我编写了一个示例,将“保存”并按预期工作。

完整的示例:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  TestModel _model = TestModel(
    'id', 'name'
  );

  _changeValue(){
    _model.setId('newId');
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          children: <Widget>[
            Container(
                padding: EdgeInsets.all(56.0),
                child: ChangeNotifierConsumer<TestModel>(
                  model: _model,
                  builder: (BuildContext context) {
                    return Column(
                      children: <Widget>[
                        Text(_model.id),
                        RaisedButton(
                          child: Text(_model.name),
                          onPressed: _changeValue,
                        )
                      ],
                    );
                  },
                )), Text(_model.id)
          ],
        )
      )
    );
  }
}


class ChangeNotifierConsumer<T extends Model> extends StatefulWidget {
  ChangeNotifierConsumer({
    Key key,
    @required this.model,
    @required this.builder,
  }) : super(key: key);

  final T model;
  final Widget Function(BuildContext context) builder;
  @override
  _ChangeNotifierConsumerState createState() => _ChangeNotifierConsumerState();
}

class _ChangeNotifierConsumerState extends State<ChangeNotifierConsumer> {
  @override
  void initState() {
    super.initState();
    widget.model.addListener(_listener);
  }

  @override
  void dispose() {
    widget.model.removeListener(_listener);
    super.dispose();
  }

  void _listener() {
    print('setstate');
    setState(() {});
  }

  @override
  Widget build(BuildContext context) => widget.builder(context);
}

abstract class Model with ChangeNotifier {

}

class TestModel extends Model {
  String _id;
  String _name;


  TestModel(this._id, this._name);

  get id => _id;
  get name => _name;

  setId(String id) {
    _id = id;
    notifyListeners();
  }

}