回答
所以,我終於找到了解決方案。非常哈克,但嘿!有用! (編輯:僅在調試模式下)。
let Foo (f:S -> A[] -> B[] -> C[] -> D[] -> unit) =
let ty = f.GetType()
let argty = [|typeof<S>; typeof<A[]>; typeof<B[]>; typeof<C[]>;typeof<D[]>|]
let mi = ty.GetMethod("Invoke", argty)
let il = mi.GetMethodBody().GetILAsByteArray()
let offset = 9//mi.GetMethodBody().MaxStackSize
let token = System.BitConverter.ToInt32(il, offset)
let mb = ty.Module.ResolveMethod(token)
match Expr.TryGetReflectedDefinition mb with
| Some ex -> printfn "success %A" e
| None -> failwith "failed"
它運作良好,即使f爲在另一組件(.DLL)或在富的呼叫發生相同的定義。 這不是完全一般的,因爲我必須定義argty是什麼,但我確信我可以寫一個函數來完成它。
在編寫此代碼後發現達斯汀對於同一問題具有類似的解決方案,儘管在C#中(請參閱here)。
編輯: 因此,這裏是一個使用示例:
open System
open Microsoft.FSharp.Quotations
[<ReflectedDefinition>]
let F (sv:int) (a:int[]) (b:int[]) (c:int[]) (d:int[]) =
let temp = a.[2] + b.[3]
c.[0] <- temp
()
let Foo (f:S -> A[] -> B[] -> C[] -> D[] -> unit) =
let ty = f.GetType()
let arr = ty.BaseType.GetGenericArguments()
let argty = Array.init (arr.Length-1) (fun i -> arr.[i])
let mi = ty.GetMethod("Invoke", argty)
let il = mi.GetMethodBody().GetILAsByteArray()
let offset = 9
let token = System.BitConverter.ToInt32(il, offset)
let mb = ty.Module.ResolveMethod(token)
mb
let main() =
let mb = Foo F
printfn "%s" mb.Name
match Expr.TryGetReflectedDefinition mb with
| None ->()
| Some(e) -> printfn "%A" e
do main()
它所做的是打印F和其AST的名字,如果該函數是一個反映定義。後
但進一步調查,碰巧這個技巧僅在調試模式下工作(和F必須是一個函數值以及一個頂級的定義),所以還不如說它是一個不可能事要做。
這裏的FSharpFunc的Invoke方法在兩個調試/發行版本的IL代碼:
調試模式:
.method /*06000007*/ public strict virtual
instance class [FSharp.Core/*23000002*/]Microsoft.FSharp.Core.Unit/*01000006*/
Invoke(int32 sv,
int32[] a,
int32[] b,
int32[] c,
int32[] d) cil managed
// SIG: 20 05 12 19 08 1D 08 1D 08 1D 08 1D 08
{
// Method begins at RVA 0x21e4
// Code size 16 (0x10)
.maxstack 9
IL_0000: /* 00 | */ nop
IL_0001: /* 03 | */ ldarg.1
IL_0002: /* 04 | */ ldarg.2
IL_0003: /* 05 | */ ldarg.3
IL_0004: /* 0E | 04 */ ldarg.s c
IL_0006: /* 0E | 05 */ ldarg.s d
IL_0008: /* 28 | (06)000001 */ call void Program/*02000002*/::F(int32,
int32[],
int32[],
int32[],
int32[]) /* 06000001 */
IL_000d: /* 00 | */ nop
IL_000e: /* 14 | */ ldnull
IL_000f: /* 2A | */ ret
} // end of method [email protected]::Invoke
釋放模式:
method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.Unit
Invoke(int32 sv,
int32[] a,
int32[] b,
int32[] c,
int32[] d) cil managed
{
// Code size 28 (0x1c)
.maxstack 7
.locals init ([0] int32 V_0)
IL_0000: nop
IL_0001: ldarg.2
IL_0002: ldc.i4.2
IL_0003: ldelem [mscorlib]System.Int32
IL_0008: ldarg.3
IL_0009: ldc.i4.3
IL_000a: ldelem [mscorlib]System.Int32
IL_000f: add
IL_0010: stloc.0
IL_0011: ldarg.s c
IL_0013: ldc.i4.0
IL_0014: ldloc.0
IL_0015: stelem [mscorlib]System.Int32
IL_001a: ldnull
IL_001b: ret
} // end of method [email protected]::Invoke
你可以看到,在發行模式中,編譯器將F的代碼嵌入到Invoke方法中,因此調用F的信息(以及檢索令牌的可能性)消失了。
如果這對你有用,你會想要接受它作爲答案。 – kersny 2009-10-17 16:46:53
你能舉一個用法例子嗎?我理解解決方案的總體思路,但我不明白爲什麼f有它的類型。 – 2009-10-19 13:55:36
這不是(容易)可能的。要注意的事情是,當你寫:
let printFunctionName f =
let mi = getMethodInfo f
printfn "%s" mi.Name
參數「F」僅僅是類型FSharpFunc < ,的實例>。所以以下都是可能的:
printFunctionName (fun x -> x + 1) // Lambda expression
printFunctionName String.ToUpper // Function value
printFunctionName (List.map id) // Curried function
printFunctionNAme (not >> List.empty) // Function composition
在這兩種情況下,有沒有直接回答這個
也許這有幫助,我知道f總是一個函數值。你建議什麼?我會採取任何破解.. – Stringer 2009-10-15 22:25:53
我不知道是否有任何種類的功能,一般的答案,但如果你的函數是簡單的( 'A - >' b),那麼你可以寫
let getMethodInfo (f : 'a -> 'b) = (FastFunc.ToConverter f).Method
謝謝,我已經嘗試過,但似乎沒有工作.. – Stringer 2009-10-15 22:50:05
下面是否幫助的程序?
module Program
[<ReflectedDefinition>]
let F x =
x + 1
let Main() =
let x = F 4
let a = System.Reflection.Assembly.GetExecutingAssembly()
let modu = a.GetType("Program")
let methodInfo = modu.GetMethod("F")
let reflDefnOpt = Microsoft.FSharp.Quotations.Expr.TryGetReflectedDefinition(methodInfo)
match reflDefnOpt with
| None -> printfn "failed"
| Some(e) -> printfn "success %A" e
Main()
是的,很像這樣,期望我不知道方法名稱(「F」)或模塊。 – Stringer 2009-10-17 15:59:01
- 1. 在int上檢索MethodInfo
- 2. 如何檢索F#中的函數名稱?
- 3. 從f調用函數f
- 4. 根據委託檢查MethodInfo
- 5. Curried函數f#
- 6. F#Powerset函數
- 7. 檢索函數數據
- 8. F#中接受函數的函數
- 9. F#函數列表
- 10. F#Suave鶯函數
- 11. F#構造函數
- 12. 關於F#函數
- 13. F#中的動態函數
- 14. F中的傳遞函數#
- 15. F中的嵌套函數#
- 16. F#中的函數'startsWithVowel'
- 17. 從函數中檢索值
- 18. 如何檢索.keydown()函數
- 19. 檢索JS函數值
- 20. Rcpp函數:f(x) - f(x)不是0
- 21. 檢索函數內部的數據
- 22. F#可變函數參數
- 23. F#初學者:從服務器檢索數據數組
- 24. C#的MethodInfo getReturnType
- 25. 使用F檢索來自Facebook圖形API的數據#
- 26. f#從函數返回部分函數
- 27. 從未知簽名的MethodInfo創建表達式函數
- 28. 檢索函數中的指針
- 29. 檢索python中的非內置函數
- 30. 結合F#異步函數
您打算如何處理MethodInfo? – Brian 2009-10-15 22:26:15
我試圖得到反映的定義,與呃..TryGetReflectedDefinition函數。 – Stringer 2009-10-15 22:36:39
我不知道F#中的任何內容,但在o'caml中,您可以使用預處理器(我不知道F#中是否有類似內容)http://groups.google.com/group/fa。 caml/browse_thread/thread/25c9706b89196140 – LB40 2009-10-26 00:20:34