2010-07-05 85 views
0

鑑於多項功能test1test2,...屬於模塊:F#動態操作讓訪問既功能和功能名稱

module Checks = 
    let test1 x = ... 
    let test2 x = ... 
    ... 

如何操作可以用來給接入(?)到函數名稱和函數本身?結果應該是這樣的:

let name, func = Checks?test1 
assert(name = "test1") 
assert(func(x) = Checks.test1(x)) //whatever x is (test1 is known to be pure) 

回答

1

下面是一些示例代碼,展示了一些此。我使用D作爲Checks模塊加上函數名稱的「動態」訪問。

module Checks = 
    let test1(x) = printfn "test1 %d" x 
    let test2(x,y) = printfn "test2 %s %d" x y 

type MyDynamic() = class end 
let D = new MyDynamic() 
let (?) (md:MyDynamic) fname : (string * ('a -> 'r)) = 
    let a = md.GetType().Assembly 
    let t = a.GetType("Program+Checks") 
    let m = t.GetMethod(fname) 
    let f arg = 
     let at = arg.GetType() 
     let fsharpArgs = 
      if at.IsGenericType && at.GetGenericTypeDefinition().FullName.StartsWith("System.Tuple`") then 
       Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(arg) 
      else 
       [| box arg |] 
     unbox(m.Invoke(null, fsharpArgs)) 
    fname, f 

let Main() = 
    let x = 42 
    let s = "foo" 
    let name, func = D?test1 
    assert(name = "test1") 
    assert(func(x) = Checks.test1(x)) 

    let name, func = D?test2 
    assert(name = "test2") 
    assert(func(s,x) = Checks.test2(s,x)) 

    System.Console.ReadKey() 

Main() 
3

您不能使用?運營商訪問模塊中的功能,因爲結構Checks?test1在語法上不正確的(這將被轉換爲(?) Checks "test",你不能用模塊名作爲值) 。

但是,應該可以對使用對象實例的類型成員(例如obj?test)執行此操作。或者,您可以編寫一個「假」對象實例(知道模塊的名稱)。然後,?的實現將查找模塊並搜索模塊中的靜態成員。

(第一種情況)的最簡單的實現應該是這樣的:

let (?) obj s = 
    let memb = obj.GetType().GetMethod(s) 
    // Return name and a function that runs the method 
    s, (fun args -> memb.Invoke(obj, args)) 

// Type that contains tests as members  
type Check() = 
    member x.test1() = 32 

// We need to create instance in order to use '?' 
let ch = Check() 
let s,f = ch?test1 

// Function 'f' takes array of objects as an argument and 
// returns object, so the call is not as elegant as it could be 
let n = ((f [| |]) :?> int) 

你也可以添加一些包裝,以使函數f的一點點更好,但我希望這表明了想法。不幸的是,這不能用於模塊。