Проверка общего типа — сохраняйте тип, а не динамический

#dart #generics

Вопрос:

У меня есть эти занятия

 class CustomPopupAction<T> extends CustomAction {
  final Icon icon;
  final List<CustomPopupActionItem<T>> actions;
  final void Function(T) onActionSelected;

  CustomPopupAction({
    required this.icon,
    required this.actions,
    required this.onActionSelected,
  });
}

class CustomPopupActionItem<T> {
  final T value;
  final Widget Function(T) itemBuilder;

  CustomPopupActionItem({
    required this.value,
    required this.itemBuilder,
  });
}
 

и я пытаюсь создать меню переполнения, которое будет работать следующим образом:

  • если кнопка видна, я создам PopupMenuButton
  • если кнопка переполнена, я создам ListTile , которая откроет диалоговое окно
  • он может содержать несколько различных типов, таких как CustomAction , CustomPopupAction<Locale> , CustomPopupAction<String>

Я строю этот ряд вот так

 if (a is CustomPopupAction) {
  return PopupMenuButton(
    icon: a.icon,
    onSelected: (i) => a.onActionSelected(i),
    itemBuilder: (context) {
      return a.actions.map((i) => PopupMenuItem(
        value: i.value,
        child: i.itemBuilder(i.value),
      )).toList();
    },
  );
} else {
  return IconButton(...);
}
 

и, наконец, мой основной код:

 ...
return OverflowMenu(
  actions: [
    CustomPopupAction<Locale>(
      icon: Icon(Icons.translate),
      actions: [
        CustomPopupActionItem<Locale>(
          value: Locale('en'),
          itemBuilder: (l) => ListTile(title: Text(l.toString()),
        ),
      ],
    onActionSelected: (l) => print(l),
  ],
);
      
 

Но это не работает для меня, я получаю исключение Expected a value of type '(dynamic) => Widget', but got one of type '(Locale) => ListTile'.

Я знаю, что это потому if (a is CustomPopupAction) , что на самом деле становится CustomPopupAction<dynamic> .

  1. могу ли я каким-то образом убедить Dart, что a nas не динамический тип и что он должен работать с реальным типом?
  2. если нет, то почему я получаю это исключение? Locale может быть присвоено dynamic переменной и ListTile явно является a Widget .
  3. могу ли я сделать это, вообще не проходя через динамику?

Комментарии:

1. Когда ты это делаешь a is CustomPopupAction , ты действительно делаешь a is CustomPopupAction<dynamic> . Если условие верно, a следовательно, будет повышено до CustomPopupAction<dynamic> . Если вы хотите избежать dynamic этого , вам нужно будет указать явный параметр типа. Если вы не знаете этот тип статически , то это по своей сути означает, что вам потребуется выполнить дополнительные проверки типов во время выполнения .

2. Спасибо, я так и думал. Какие проверки типа времени выполнения вы имеете в виду? Например, проверьте точный тип, например CustomPopupAction<Locale> ? Это будет много проверок. Также разве вы не знаете, почему я получаю это исключение, когда эти типы (Locale -> динамический, ListTile ->> Виджет) должны быть совместимы?