如何通过反射调用F#泛型函数?
解决F#泛型函数的动态反射调用问题
问题核心
你遇到的问题本质是:直接传递的qux是未绑定类型参数的泛型函数定义,而非针对特定't类型的具体化函数实例。当传入Foo<int>和Bar<int>这类具体类型参数时,函数的类型参数't并未被正确绑定,导致类型不匹配抛出异常。
解决方案
需要先通过反射获取泛型函数的定义,再用运行时拿到的System.Type对象构造出对应类型的具体化函数,之后再调用这个具体化后的函数。
修改后的完整代码
type Foo<'t> = { Foo : 't } type Bar<'t> = { Bar : 't } type Qux<'t> = { Foo : 't Bar : 't } let qux (x : Foo<'t>) (y : Bar<'t>) : Qux<'t> = { Foo = x.Foo Bar = y.Bar } open FSharp.Reflection open System // 获取指定类型参数的泛型函数实例 let getGenericFunctionInstance (genericFunc : obj) (typeArgs : Type[]) = let funcType = genericFunc.GetType() // 生成绑定了具体类型参数的函数类型 let specificFuncType = funcType.MakeGenericType(typeArgs) // 创建具体化后的函数实例(F#泛型函数需传入原定义实例初始化) Activator.CreateInstance(specificFuncType, [| genericFunc |]) let invokeDynamic (specificFunc : obj) (args : obj seq) = let rec loop (next : obj) (args : obj list) : obj = match args with | [] -> next | x :: xs -> let fnType = next.GetType() if FSharpType.IsFunction fnType then let methodInfo = fnType.GetMethods() |> Seq.filter (fun m -> m.Name = "Invoke" && Array.length (m.GetParameters()) = 1) |> Seq.head let result = methodInfo.Invoke(next, [| x |]) loop result xs else failwithf "Object was not of a function type: %s" fnType.FullName loop specificFunc (List.ofSeq args) // 示例1:运行时指定't为int let intType = typeof<int> let quxInt = getGenericFunctionInstance qux [| intType |] invokeDynamic quxInt [ box { Foo = 123 }; box { Bar = 456 } ] |> printfn "%A" // 输出:{ Foo = 123; Bar = 456 } // 示例2:运行时指定't为obj let objType = typeof<obj> let quxObj = getGenericFunctionInstance qux [| objType |] invokeDynamic quxObj [ box { Foo = box 123 }; box { Bar = box 456 } ] |> printfn "%A" // 输出:{ Foo = 123; Bar = 456 }
关键步骤说明
- 提取泛型函数定义:通过
genericFunc.GetType()获取泛型函数的原始类型(比如qux的类型是FSharpFunc<Foo<'t>, FSharpFunc<Bar<'t>, Qux<'t>>>的泛型定义)。 - 生成具体化类型:调用
MakeGenericType方法,传入运行时的Type数组,生成绑定了具体类型参数的函数类型。 - 构造具体化函数实例:用
Activator.CreateInstance创建具体化后的函数对象,传入原泛型函数实例作为构造参数(F#泛型函数的类型设计要求此初始化方式)。 - 调用具体化函数:使用
invokeDynamic调用已经绑定类型参数的函数,此时参数类型能完全匹配,避免类型错误。
内容的提问来源于stack exchange,提问作者sdgfsdh
相关产品推荐
相关产品推荐

