Повышение уровня Dart на самом деле не является повышением

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

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>());
});

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

ИЗМЕНИТЬ:

[удалено]

РЕДАКТИРОВАТЬ 2:

[удалено]

Редактировать 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>

person Nakash Kumar    schedule 12.12.2020    source источник
comment
Ваш пример не показывает вашу проблему. Вы можете видеть в выводе, что он ожидает Right<dynamic, VideoStream>:<Right(VideoStream)>, но получил Right<Failure, VideoStream>:<Right(VideoStreamModel)>. Failure не является dynamic, поэтому он терпит неудачу.   -  person julemand101    schedule 12.12.2020
comment
Если вам не подходит первая часть Right, вы можете попробовать: Right<Object, VideoStream>:<Right(VideoStreamModel)>   -  person julemand101    schedule 12.12.2020
comment
Пожалуйста, предоставьте рабочий пример, который воспроизводит вашу проблему. Прямо сейчас вы предоставляете много подробностей о чем-то, что на самом деле не является сутью вашей проблемы.   -  person julemand101    schedule 12.12.2020
comment
@ julemand101, вы можете запустить код в редактировании 3.   -  person Nakash Kumar    schedule 12.12.2020
comment
Спасибо, я вижу проблему. Обновлю свой ответ. :)   -  person julemand101    schedule 12.12.2020
comment
Обновите мой ответ.   -  person julemand101    schedule 12.12.2020


Ответы (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.

person julemand101    schedule 12.12.2020