F#|Fable Thoth Decode Auto泛型封装调用运行时generics读取错误
问题成因
该问题由Fable的泛型代码生成逻辑与Thoth Decode Auto的元数据依赖共同导致:
- Thoth Decode Auto的自动解码能力依赖编译阶段为每个具体类型生成的序列化/反序列化元数据,元数据生成的前提是编译器能在
Decode.Auto.fromString的调用点明确知道传入的泛型实参类型。 - 你封装的
decodeData<'a>是无约束的开放泛型函数,Fable默认不会为所有可能的'a类型预先生成解码元数据,且调用decodeData<String[]>时,泛型参数的类型信息默认不会透传给函数内部的Decode.Auto.fromString<'a>调用,导致运行时找不到对应类型的元数据,抛出Cannot read properties of null (reading 'generics')错误。 - 直接调用
Decode.Auto.fromString<String[]>(encodedData)时,编译器在调用点可直接获取到泛型实参为String[],会提前生成对应元数据并传入解码方法,因此运行正常。
解决方法
下面是三种经过验证的可行方案,优先推荐第一种改动最小的方案:
方案1:为泛型函数添加
[<Inline>]特性
标记内联后Fable编译器会在每次调用decodeData时把函数逻辑展开到调用点,直接捕获到每次调用的具体泛型实参,生成对应解码元数据:[<Inline>] let decodeData<'a> (encodedData: string) = Decode.Auto.fromString<'a>(encodedData)如果需要强制调用方显式指定类型实参避免隐式类型推断错误,可以额外加
[<RequiresExplicitTypeArguments>]特性。方案2:显式传递解码器参数
若不希望使用内联,可以调整函数定义要求调用方传入对应类型的解码器:let decodeData<'a> (decoder: Decoder<'a>) (encodedData: string) = Decode.fromString decoder encodedData调用时通过
Decode.Auto.generateDecoder<String[]>()获取对应类型的解码器传入即可。方案3:针对常用类型做特化封装
如果你的业务场景只需要固定几种类型的解码,可以直接针对每种类型写特化的解码函数,完全规避泛型参数传递问题:let decodeStringArray (encodedData: string) = Decode.Auto.fromString<string[]>(encodedData)
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

