實際上,如果您知道f#函數(表示爲靜態.NET方法的MethodInfo對象)也有一個方法GetGenericMethodDefinition
其實很容易。 這似乎像f#中的typedefof< >
運算符一樣工作,以獲得MethodInfo對象的通用定義。
鑑於該功能確實是一種通用功能,可以使用IsGenericMethodDefinition
進行檢查。
下面一個SignaturePrinter,它與任何泛型函數運行任何類型的通用數據類型的
type Box<'a, 'b> = Box of 'a * 'b
首先幾個幫手
let getFn e =
let rec name e =
match e with
| Call (x, mi, y) -> mi
| Lambda (_, body) -> name body
| _ -> failwith <| sprintf "not a function %A" e
name e
let join sep (ss: string []) = String.Join(sep, ss)
let wrap sepB sepE s = sprintf "%s%s%s" sepB s sepE
let generics (ts:Type[]) =
if Array.length ts > 0 then
ts
|> Array.map (fun x -> x.Name)
|> join ","
|> wrap "<" ">"
else ""
let genericDef (mi:MethodInfo) = mi.GetGenericMethodDefinition()
然後簽名打印機使用自動報價
type SignaturePrinter = class end
with
static member Print ([<ReflectedDefinition>] f : Expr<'a -> 'b>) =
let mi = getFn f |> genericDef
let typeSig (t:Type) =
let sanitizedName (n:string) = n.Split('`') |> Array.head
[|sanitizedName t.Name; generics t.GenericTypeArguments|]
|> join ""
let fnParams (m:MethodInfo) =
m.GetParameters()
|> Array.map (fun x -> typeSig x.ParameterType)
|> join " -> "
[|
[|mi.Name; mi.GetGenericArguments() |> generics; " ::"|] |> join ""
fnParams mi
typeSig mi.ReturnType
|]
|> join " -> "
一些通用的測試方法
let iToS<'x, 'y> (b : Box<'x, 'y>) : Box<string, 'y> =
let (Box (i,v)) = b
Box ((sprintf "%A" i), v)
let iToB (Box (i:int, v:'a)) = Box (i > 0, v)
let fixedRet (Box (i:int, v:'z)) = Box (true, false)
並測試代碼
let s1 = SignaturePrinter.Print iToS
//iToS<x,y> :: -> Box<x,y> -> Box<String,y>
let s2 = SignaturePrinter.Print fixedRet
//fixedRet<z> :: -> Box<Int32,z> -> Box<Boolean,Boolean>
let s3 = SignaturePrinter.Print iToB
//iToB<a> :: -> Box<Int32,a> -> Box<Boolean,a>