2009-10-15 11 views
11

के MethodInfo पुनर्प्राप्त करें मैं एक फ़ंक्शन लिखना चाहता हूं जो एक फ़ंक्शन को तर्क के रूप में लेता है और सिस्टम को वापस लौटाता है। Reflection.MethodInfo f से जुड़ा हुआ है।एक F # फ़ंक्शन

मुझे यकीन नहीं है कि यह संभव है या नहीं।

+0

आप MethodInfo के साथ क्या करना चाहते हैं? – Brian

+0

मैं प्रतिबिंबित परिभाषा को erm के साथ प्राप्त करने का प्रयास करता हूं ..TryGetReflectedDefinition फ़ंक्शन का प्रयास करें। – Stringer

+1

मुझे एफ # में कुछ भी पता नहीं है लेकिन ओ'कैम में आप प्री-प्रोसेसर का उपयोग कर ऐसा कर सकते हैं (मुझे नहीं पता कि एफ # में कुछ समान है या नहीं) http://groups.google.com/group/fa। caml/Browse_thread/thread/25c9706b89196140 – LB40

उत्तर

5

तो, मुझे अंततः एक समाधान मिला। बहुत हैकी, लेकिन हे! यह काम करता हैं! (संपादित करें: केवल डीबग मोड में)।

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" 

यह अच्छी तरह से काम करता है, भले ही एफ किसी अन्य असेंबली (.dll) में परिभाषित किया गया हो या वही जहां फू का कॉल होता है। यह अभी तक सामान्य नहीं है क्योंकि मुझे परिभाषित करना है कि क्या तर्क है, लेकिन मुझे यकीन है कि मैं ऐसा फ़ंक्शन लिख सकता हूं जो ऐसा करता है।

इस कोड को लिखने के बाद बाहर निकलता है कि डस्टिन के पास एक ही समस्या के समान समाधान है, हालांकि सी # में देखें (इसे 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() 

क्या यह एफ, और उसके एएसटी के नाम प्रिंट कर रहा है समारोह एक परिलक्षित परिभाषा है अगर करता है।

लेकिन आगे की जांच पड़ताल के बाद, यह होता है कि इस हैक केवल डिबग मोड में काम करता है (और एफ एक समारोह मूल्य के रूप में अच्छी तरह से एक शीर्ष स्तर परिभाषा के रूप में हो गया है), तो के रूप में अच्छी तरह से कह सकते हैं कि यह एक असंभव बात है करने के लिए।

डीबग मोड::

.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 

आप देख सकते हैं कि रिलीज में

यहाँ दोनों डिबग/रिलीज निर्माण में FSharpFunc के आह्वान विधि के आईएल कोड है मोड, कंपाइलर एफ के कोड को इनवॉक विधि में रेखांकित करता है, इसलिए कॉलिंग (और टोकन को पुनर्प्राप्त करने की संभावना) की जानकारी समाप्त हो गई है ..

+0

यदि यह आपके लिए काम करता है, तो आप इसे उत्तर के रूप में स्वीकार करना चाहते हैं। – kersny

+0

क्या आप एक उदाहरण उदाहरण दे सकते हैं? मैं समाधान के सामान्य विचार को समझता हूं, लेकिन मुझे नहीं लगता कि एफ के पास किस तरह का प्रकार है। –

2

यह (आसानी से) संभव नहीं है।

let printFunctionName f = 
    let mi = getMethodInfo f 
    printfn "%s" mi.Name 

पैरामीटर 'एफ' बस प्रकार 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 

या तो मामले में इस

+0

शायद यह मदद करता है, मुझे पता है कि f हमेशा एक फ़ंक्शन मान होता है। आप क्या सिफारिश करते हैं? मैं कोई हैक ले जाऊंगा .. – Stringer

1

करने के लिए कोई सीधा जवाब अगर वहाँ समारोह के किसी भी प्रकार के लिए एक सामान्य जवाब है मैं नहीं जानता कि वहाँ है, लेकिन अपने कार्य है अगर सरल ('एक ->' ख) तो आप लिख सकते हैं

let getMethodInfo (f : 'a -> 'b) = (FastFunc.ToConverter f).Method

+0

धन्यवाद, मैंने कोशिश की है, लेकिन काम नहीं लग रहा है .. – Stringer

3

मदद नीचे कार्यक्रम करता है?

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()  
+0

हाँ सही, बहुत कुछ, उम्मीद है कि मुझे विधि का नाम ("एफ") या मॉड्यूल नहीं पता है । – Stringer

संबंधित मुद्दे

 संबंधित मुद्दे