Я пытаюсь преобразовать объект подкласса, но он не работает. Следующая программа компилируется без ошибок.
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
, вы можете попробовать: Right<Object, VideoStream>:<Right(VideoStreamModel)>
Пожалуйста, предоставьте рабочий пример, который воспроизводит вашу проблему. Прямо сейчас вы предоставляете много подробностей о чем-то, что на самом деле не является сутью вашей проблемы.
@ julemand101, вы можете запустить код в редактировании 3.
Спасибо, я вижу проблему. Обновлю свой ответ. :)
Обновите мой ответ.
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
.
Ваш пример не показывает вашу проблему. Вы можете видеть в выводе, что он ожидает
Right<dynamic, VideoStream>:<Right(VideoStream)>
, но получилRight<Failure, VideoStream>:<Right(VideoStreamModel)>
.Failure
не являетсяdynamic
, так что это причина, почему он терпит неудачу.