stream_channel/MultiChannel..VirtualChannel..sink.add(msg) 在使用带有类型的消息(例如 )时会抛出异常
我正在按照API文档中最新版本(2.1.4)的示例代码进行学习,链接中的示例为 示例代码。我的 async 版本是2.13.1(截至目前也是最新版本)。
具体来说,我正在创建一个 MultiChannel.VirtualChannel,从一个 StreamChannelController 开始,其中通过泛型表示法显式声明为特定类型的消息被 sink 标记(例如 String)。但它抛出了这个异常:type 'List<Object?>' is not a subtype of type 'String' of 'data'。
这段非常简单的代码:
import 'package:stream_channel/stream_channel.dart';
void main() {
var dummyCtrl1 = StreamChannelController<String>();
var multiChannel = MultiChannel<String>(dummyCtrl1.local);
var channel1 = multiChannel.virtualChannel();
channel1.sink.add("AAA");
}
抛出以下异常:
type 'List<Object?>' is not a subtype of type 'String' of 'data'
#0 _GuaranteeSink.add (package:stream_channel/src/guarantee_channel.dart:118:14)
#1 _MultiChannel.virtualChannel.<anonymous closure> (package:stream_channel/src/multi_channel.dart:212:35)
#2 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778:10)
#3 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381:11)
#4 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:312:7)
#5 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:798:19)
#6 _StreamController._add (dart:async/stream_controller.dart:663:7)
#7 _StreamController.add (dart:async/stream_controller.dart:618:5)
#8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1778:10)
#9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381:11)
#10 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:312:7)
#11 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:798:19)
#12 _StreamController._add (dart:async/stream_controller.dart:663:7)
#13 _StreamController.add (dart:async/stream_controller.dart:618:5)
#14 _StreamSinkWrapper.add (dart:async/stream_controller.dart:898:13)
#15 _GuaranteeSink.add (package:stream_channel/src/guarantee_channel.dart:125:12)
#16 main (file:///.../fails.dart:8:17)
#17 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#18 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)
但如果完全移除 <String> 或改为 <dynamic>,就不会抛出异常。
_GuaranteeSink.add (package:stream_channel/src/guarantee_channel.dart:118:14) 是:
@override
/*118*/ void add(T data) {
if (_closed) throw StateError('Cannot add event after closing.');
if (_inAddStream) {
throw StateError('Cannot add event while adding stream.');
}
if (_disconnected) return;
_inner.add(data);
}
而 _MultiChannel.virtualChannel.<anonymous closure> (package:stream_channel/src/multi_channel.dart:212:35) 是:
controller.local.stream.listen(
/*212*/ (message) => _inner!.sink.add(<Object?>[outputId, message]),
onDone: () => _closeChannel(inputId, outputId));
return VirtualChannel._(
this, outputId, controller.foreign.stream, controller.foreign.sink);
}
一个错误报告已经提交(至今尚无回应)。
是否只有移除/放宽消息类型才是解决办法?(我的实际用例是使用我自己的消息类,可以安全地简化为一个Map。)
解决方案
这之所以会这样,是因为在解码JSON时——尤其是在 dart2wasm / WebAssembly场景下——数组中的数值在运行时可能会返回为 double,而不是 int。
内部,MultiChannel 期望通道ID是一个 int,并执行如下的类型转换:
final id = msg[0] as int;
如果解码后的值实际上是一个 double(例如 1.0),则类型转换失败,错误为:
type 'double' is not a subtype of type 'int'
修复
在转换为 int 之前,先经过 num 的强制转换:
final id = (msg[0] as num).toInt();
这可同时正确处理 int 和 double。
额外信息
这似乎是 stream_channel 中的一个已知问题。
升级该包可能会解决它:
dependencies:
stream_channel: ^2.1.2