Dynamic F#动态运算符,允许访问函数和函数名
给定许多函数,Dynamic F#动态运算符,允许访问函数和函数名,dynamic,f#,Dynamic,F#,给定许多函数,test1,test2。。。属于某个模块: 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
test1
,test2
。。。属于某个模块:
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)
您不能使用
?
运算符访问模块中的函数,因为构造检查?test1
在语法上不正确(这将转换为(?)检查“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”变得更好一些,但我希望这能说明这一点。不幸的是,这对模块不起作用。您不能使用
?
操作符访问模块中的函数,因为构造检查?test1
在语法上不正确(这将转换为(?)检查“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”变得更好一些,但我希望这能说明这一点。不幸的是,这不适用于模块。以下是一些示例代码,展示了其中的一些功能。我使用
D
作为检查
模块加函数名的“动态”访问
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()
下面是一些示例代码,展示了其中的一些内容。我使用
D
作为检查
模块加函数名的“动态”访问
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()