参数类型一致的F#联合类型:如何通过构造函数获取UnionCaseInfo?
问题描述
我们定义了一个包含3个分支的联合类型(DU),每个分支都以Object类型作为参数:
type DU = | X of Object | Y of Object | Z of Object
已知FSharp.Reflection.FSharpType命名空间中的GetUnionCases函数,传入DU的类型信息后可返回UnionCaseInfo数组。
我们希望实现一个函数f: ('T -> DU) -> UnionCaseInfo,满足:
f X返回分支X对应的UnionCaseInfof Y返回分支Y对应的UnionCaseInfo- 以此类推
由于当前所有分支的参数类型都是Object(多对一映射),此前的两种常规方法都不适用:
- 若DU分支无参数,可通过
typeof<DU>的GetProperties()获取单例实例关联对应UnionCaseInfo - 若各分支参数类型不同,可通过构造函数的
Invoke方法的类型关联分支
请问这个需求是否可行?
可行方案
可行,核心思路是利用独特标记对象结合联合类型的反射解析来区分分支:
- 创建一个唯一的标记类型(避免和其他
Object类型冲突):
type Marker() = class end let marker = Marker()
- 实现函数
f:传入分支构造函数时,先用标记对象构造一个DU实例,再通过FSharpValue.GetUnionFields解析该实例,提取对应的UnionCaseInfo:
open FSharp.Reflection let f (ctor: obj -> DU) = let duInstance = ctor marker let unionCase, _ = FSharpValue.GetUnionFields(duInstance, typeof<DU>) unionCase
- 验证使用:
// 获取各分支的UnionCaseInfo let xCase = f X let yCase = f Y let zCase = f Z // 输出分支名称验证 printfn "%s" xCase.Name // 输出 "X" printfn "%s" yCase.Name // 输出 "Y" printfn "%s" zCase.Name // 输出 "Z"
原理说明
每个分支的构造函数会用标记对象生成对应分支的实例,FSharpValue.GetUnionFields可以直接从实例中提取出其所属的UnionCaseInfo,完全不需要依赖参数类型的差异。标记对象仅用于临时构造实例,不会影响业务逻辑,且因为是自定义类型,不会和其他可能传入的Object类型混淆。
内容的提问来源于stack exchange,提问作者RMills330
相关产品推荐
相关产品推荐

