Поле доступа к объекту подкласса без приведения

#flutter #dart #inheritance #polymorphism

Вопрос:

Учитывая следующие классы:

 abstract class ParentState extends Equatable {
  const SomeState();
}

class SomeState extends ParentState {
  const SomeState({required this.someField});

  final String someField;

  @override
  List<Object> get props => [someField];
}
 

Я хочу получить доступ someField , если текущее состояние соответствует типу SomeState в моем mapEventToState методе, но компилятор этого не разрешает:

  @override
  Stream<ParentState> mapEventToState(
    ParentEvent event,
  ) async* {
    if (state is SomeState) {
        print(state.someField); // Error: The getter 'someField' isn't defined for the type 'ParentState'.
    }
}
 

Однако, если я создам ParentState переменную вручную, она будет работать так, как ожидалось:

 ParentState state = SomeState(someField: 'test');

if (state is SomeState) {
   print(state.someField); // Works.
}
 

Кроме того, ручное литье mapEventToState работает, но это не должно требоваться:

 if (state is SomeState) {
    print((state as SomeState).someField); // Works.
}
 

Чего мне не хватает?

Ответ №1:

В вашем первом примере с ошибкой похоже state , что это поле в окружающем классе с автоматически сгенерированным средством получения и установки.

Однако, с точки зрения анализатора, также может state быть функция получения, которая позволяет возвращать другой объект каждый раз, когда вызывается средство получения. Таким образом, при первом вызове геттера в if инструкции геттер может вернуть SomeState объект, но в if теле геттер может вернуть совершенно другой объект без someField геттера.

Чтобы обойти эту проблему, вам просто нужно создать локальную копию вашей переменной в функции и использовать эту копию вместо поля класса:

 @override
Stream<ParentState> mapEventToState(
  ParentEvent event,
) async* {
  final stateCopy = state;
  if (stateCopy is SomeState) {
      print(stateCopy.someField);
  }
}
 

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

1. state является добытчиком. Вполне логично, что сейчас это не работает. Спасибо.