具有任意签名的函数生成

时间:2012-08-02 06:42:32

标签: .net generics reflection f# reflection.emit

假设您要编写一个函数“gen”,该函数生成一个带有由类型列表给出的签名的函数:

let gen (sig:Type list) = ....

let sig = [ typeof<int>; typeof<int[]>; typeof<float> ]
let func = gen sig
then func is of type: int -> int[] -> float -> unit

我想到了两种可能的解决方案:

a)使用Reflect Emit,但我不知道我们是否可以通过这种方式使IntelliSense正常工作? 反射Emit似乎创建了新的.net代码,IntelliSense可能看不到它,因此它可能无法在编译时验证代码。

b)使用类型提供者,但我担心太重,可能不实用。

c)使用泛型,如gen<'T1> (sig:Type list) : 'T2 -> unit,这可能需要递归调用,但我没有想出如何执行此操作。

我更喜欢方法c),因为它是轻量级的,可以在编译时检查。或者有替代方法吗?

2 个答案:

答案 0 :(得分:1)

请参阅MakeFunctionhttp://msdn.microsoft.com/en-us/library/ee353497

Reflection.Emit更慢,但更容易使用,可能适合您的目的。

答案 1 :(得分:1)

你已经问过如何用一些给定的签名生成函数,但是问题忽略了关于函数体的观点。

假设你有办法设置这个主体,一个可能的解决方案可能看起来像这样(警告:因为内部使用反射,因此速度很慢):

module F = 
    type FST = Microsoft.FSharp.Reflection.FSharpType
    type FSV = Microsoft.FSharp.Reflection.FSharpValue

    let mkFunction (handler : obj list -> obj) : 'T = 
        if not (FST.IsFunction typeof<'T>) then failwith "Function type expected"
        let rec chain args ty = 
            let dty, rty = FST.GetFunctionElements ty
            let impl = 
                if FST.IsFunction rty then 
                    fun o -> chain (o::args) rty
                else
                    fun o -> handler(List.rev (o::args))
            FSV.MakeFunction(ty, impl)
        chain [] typeof<'T> :?> 'T
let f : int -> (int -> int) -> string = 
    F.mkFunction <| 
        fun [:? int as a; :? (int -> int) as f] -> 
            box (string (f a))

如果您想使用System.Type列表表示所需的签名 - 请向intellisence说再见