Dart "upcasting" на самом деле не является upcasting

Я пытаюсь преобразовать объект подкласса, но он не работает. Следующая программа компилируется без ошибок.

VideoStreamModel model = VideoStreamModel("");
VideoStream entity = model;
print(model); // prints VideoStreamModel
print(entity); // prints VideoStreamModel
print(entity as VideoStream); // prints VideoStreamModel
print(cast<VideoStream>(model)); // prints VideoStreamModel

Я написал тестовый пример, чтобы проверить связь двух вышеуказанных классов, и он проходит.

test('should be a subtype of VideoStream', () async {
    expect(model, isA<VideoStream>());
});

В чем здесь может быть проблема?

Обновлено:

[удалено]

Обновлено еще раз:

[удалено]

Редактировать 3:

Вот полный код, воспроизводящий ошибку.

import 'package:equatable/equatable.dart';
import 'package:test/test.dart';

class A extends Equatable {
  final String x;
  
  A(this.x);

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

class B extends A {
  B(String x) : super(x);

  A method() {
    B b = B(x); // doing A b = A(x) makes the test pass
    return b;
  }
  
}

void main() {

  B b = B("");

  test('test', () async {
      final expected = A(b.x);
      final actual = b.method();
      expect(actual, expected);
  });
}

Он генерирует следующую ошибку утверждения:

Expected: A:<A>
  Actual: B:<B>

Ваш пример не показывает вашу проблему. Вы можете видеть в выводе, что он ожидает Right<dynamic, VideoStream>:<Right(VideoStream)>, но получил Right<Failure, VideoStream>:<Right(VideoStreamModel)>. Failure не является dynamic, так что это причина, почему он терпит неудачу.

julemand101 12.12.2020 13:04

Если вам не подходит первая часть Right, вы можете попробовать: Right<Object, VideoStream>:<Right(VideoStreamModel)>

julemand101 12.12.2020 13:06

Пожалуйста, предоставьте рабочий пример, который воспроизводит вашу проблему. Прямо сейчас вы предоставляете много подробностей о чем-то, что на самом деле не является сутью вашей проблемы.

julemand101 12.12.2020 13:19

@ julemand101, вы можете запустить код в редактировании 3.

Nakash Kumar 12.12.2020 13:43

Спасибо, я вижу проблему. Обновлю свой ответ. :)

julemand101 12.12.2020 13:44

Обновите мой ответ.

julemand101 12.12.2020 14:04
2
6
616
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

print вызывает toString() объект, на который вы указываете (в данном случае VideoStreamModel), который знает, к какому типу он относится. При приведении вы ничего не меняете в самом объекте, а только то, как компилятор должен видеть объект, когда он определяет, разрешено ли вам использовать данную типизированную переменную для указания на объект.

Поэтому, когда вы делаете entity as VideoStream, вы на самом деле просто говорите компилятору, что вы «обещаете», что entity можно рассматривать как VideoStream. Но во время выполнения это приведение будет проверено, чтобы убедиться, что оно верно.

Все это на самом деле не проблема, поскольку вы никогда не должны проверять конкретный тип объекта при программировании Dart, а вместо этого использовать оператор is, который проверяет, совместим ли данный объект с данным интерфейсом.

Так, например, (entity is VideoStream) вернется true.

Обновленная часть

Ваша проблема, кажется, заключается в неправильном понимании использования Equatable. Важно отметить, что Equatable не только использует элементы из props, чтобы определить, равны ли два объекта, но также смотрит на runtimeType. Вы можете увидеть это из реализации:

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Equatable &&
          runtimeType == other.runtimeType &&
          equals(props, other.props);

https://github.com/felangel/equatable/blob/master/lib/src/equatable.dart#L46

Это значит, что:

  A a = A("");
  B b = B("");
  print(a == b); // false

Когда вы используете expect без какого-либо сопоставления, он просто выполнит операцию ==, которая указана в документации:

matcher может быть значением, и в этом случае оно будет заключено в сопоставитель равных

Поскольку мы (как указывалось ранее) не можем изменить runtimeType объекта после его создания, вам необходимо реализовать свой собственный ==, если вы хотите, чтобы два экземпляра объекта рассматривались как равные, поскольку equatable видит только два объекта как равные, если они оба созданы из того же класса и содержит те же значения, определенные с помощью props.

Другие вопросы по теме