如何在Dart中防止函数强制转换异常



我不知道如何在保持函数参数类型的存储不可知的情况下存储函数。我尝试实现一个用于编码/解码的json注册表。解码工作得很好,但当涉及到编码时,我在运行时上遇到了这个错误

E/flutter ( 4637): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type '(QuotationRequest) => Map<String, dynamic>' is not a subtype of type '(Object) => Map<String, dynamic>'
E/flutter ( 4637): #0      JsonifyRegistry.encode (package:ridecube/src/commons/io/jsonify.dart:31:21)
...

当我叫这个:

final registry = JsonifyRegistry()
..register<QuotationRequest>(encoder: (_) => _.toJson(), decoder: (_) => QuotationRequest.fromJson(_));
final QuotationRequest data = QuotationRequest();
registry.encode(data); // <-- issue here

因此,如果可能的话,我很好奇如何在飞镖函数对象中进行正确的投射。

// jsonify.dart
typedef Json = Map<String, dynamic>;
typedef JsonifyEncoder<T> = Json Function(T object);
typedef JsonifyDecoder<T> = T Function(Json encoded);
class JsonifyRegistryEntry<T> {
JsonifyRegistryEntry({required this.encoder, required this.decoder});
final JsonifyEncoder<T> encoder;
final JsonifyDecoder<T> decoder;
}
class JsonifyRegistry {
final Map<Type, JsonifyRegistryEntry<Object>> _reg = {};
void register<T>({required JsonifyEncoder<T> encoder, required JsonifyDecoder<T> decoder}) =>
registerEntry(JsonifyRegistryEntry<T>(encoder: encoder, decoder: decoder));
void registerEntry<T>(JsonifyRegistryEntry<T> entry) {
_reg[T] = entry as JsonifyRegistryEntry<Object>;
}
T decode<T>(Json encoded) {
assert(_reg.containsKey(T), 'unknown type for encoding/decoding. You need to register $T first!');
return _reg[T]!.decoder(encoded) as T;
}
Json encode<T>(T object) {
assert(_reg.containsKey(T), 'unknown type for encoding/decoding. You need to register $T first!');
return _reg[T]!.encoder(object!); //line 31
}
}

注意

我当然知道为什么要阻止这种情况,但我仍在努力为我的实现找到解决方案。

简单解释:

typedef Fu1 = int Function(Object);
typedef Fu2 = int Function(int);
void main() {
final Fu2 fu2 = (x) => x;
final Fu1 fu1 = fu2 as Fu1; // error here Closure 'main_closure': type '(int) => int' is not a subtype of type '(Object) => int'
// if this wasn't the case you would get
// an error as soon as you make a call like
// this: fu1('string');
}

这是一个可能的解决方案,但我不喜欢用方法替换属性encoder。。也许你们能想出一个更好的建议。

class JsonifyRegistryEntry<T> {
JsonifyRegistryEntry({required JsonifyEncoder<T> encoder, required this.decoder}): _encoder = encoder;
final Function _encoder;
JsonifyEncoder<E> encoder<E>() => _encoder as JsonifyEncoder<E>;
final JsonifyDecoder<T> decoder;
}
// in JsonifyRegistry:
Json encode<T>(T object) {
assert(_reg.containsKey(T), 'unknown type for encoding/decoding. You need to register $T first!');
return _reg[T]!.encoder<T>()(object!);
}

最新更新