Dart "upcasting" 实际上并不是向上转型
Dart "upcasting" is not actually 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>());
});
这可能是什么问题?
编辑:
[已删除]
编辑 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>
print
在您指向的对象上调用 toString()
(在本例中为 VideoStreamModel
),它知道它是什么类型。转换时,您不会更改对象本身的任何内容,而只会更改编译器在确定是否允许您使用给定类型的变量指向对象时应该如何查看对象。
因此,当您执行 entity as VideoStream
时,您实际上只是在告诉编译器您“承诺”entity
可以被视为 VideoStream
。但在运行时,将测试此转换以查看其是否为真。
所有这一切都不是问题,因为在 Dart 编程时你永远不应该测试对象的特定类型,而是使用 is
运算符来测试给定对象是否与给定的接口。
所以,例如,(entity is VideoStream)
将 return 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
can be a value in which case it will be wrapped in an equals matcher
由于我们(如前所述)无法在对象创建后更改其运行时类型,因此如果您希望两个对象实例被视为相等,则需要实现自己的 ==
,因为 equatable
仅当两个对象都是从相同的 class 创建并且包含用 props
.
定义的相同值时才认为它们相等
我正在尝试向上转换子类对象,但它不起作用。 下面的程序编译没有任何错误。
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>
print
在您指向的对象上调用 toString()
(在本例中为 VideoStreamModel
),它知道它是什么类型。转换时,您不会更改对象本身的任何内容,而只会更改编译器在确定是否允许您使用给定类型的变量指向对象时应该如何查看对象。
因此,当您执行 entity as VideoStream
时,您实际上只是在告诉编译器您“承诺”entity
可以被视为 VideoStream
。但在运行时,将测试此转换以查看其是否为真。
所有这一切都不是问题,因为在 Dart 编程时你永远不应该测试对象的特定类型,而是使用 is
运算符来测试给定对象是否与给定的接口。
所以,例如,(entity is VideoStream)
将 return 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
can be a value in which case it will be wrapped in an equals matcher
由于我们(如前所述)无法在对象创建后更改其运行时类型,因此如果您希望两个对象实例被视为相等,则需要实现自己的 ==
,因为 equatable
仅当两个对象都是从相同的 class 创建并且包含用 props
.