FSharp 中的动态函数调用



是否可以采用FSharp函数并将其转换为动态函数,或者将来FSharp会这样的东西吗?

let func (a:int) (b:int) : int =
    a + b
let dynamicFunc = FSharpFunc.ToDynamicFunc(func)
let argumentList = [1; 2]
let object = dynamicFunc argumentList 
let result = object :?> int

看来您当前必须回退到标准反射(如下所示:按名称调用 F# 函数(,但是,这种方法似乎非常脆弱。主要是因为没有真正的保证它有效,你必须知道幕后发生了什么。

像这样的东西可以用来包装任何函数并动态地做事。

let wrapFun (x:'f) : 'f =
    let args = FSharp.Reflection.FSharpType.GetFunctionElements <| x.GetType()
    let runner (any:obj list) : obj =
        // Do extra things
        FSharpFunc.DynamicInvoke x
    FSharp.Reflection.FSharpValue.MakeFunction (typeof<'f>, runner) :?> 'f

F# 支持动态调用运算符。但你必须实现你的。下面是取自 http://www.fssnip.net/2U/title/Dynamic-operator-using-Dynamic-Language-Runtime 的示例实现

// Reference C# implementation of dynamic operations
#r "Microsoft.CSharp.dll"
open System
open System.Runtime.CompilerServices
open Microsoft.CSharp.RuntimeBinder
// Simple implementation of ? operator that works for instance
// method calls that take a single argument and return some result
let (?) (inst:obj) name (arg:'T) : 'R =
  // TODO: For efficient implementation, consider caching of call sites 
  // Create dynamic call site for converting result to type 'R
  let convertSite = 
    CallSite<Func<CallSite, Object, 'R>>.Create
      (Binder.Convert(CSharpBinderFlags.None, typeof<'R>, null))
  // Create call site for performing call to method with the given
  // name and a single parameter of type 'T
  let callSite = 
    CallSite<Func<CallSite, Object, 'T, Object>>.Create
      (Binder.InvokeMember
        ( CSharpBinderFlags.None, name, null, null, 
          [| CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null);
             CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) |]))
  // Run the method call using second call site and then 
  // convert the result to the specified type using first call site
  convertSite.Target.Invoke
    (convertSite, callSite.Target.Invoke(callSite, inst, arg))

您可以按如下方式使用它

// Dynamically invoke 'Next' method of 'Random' type
let o = box (new Random())
let a : int = o?Next(10)

至于参数,你必须将它们作为Tuple传递,比如

target?method(param1, param2)这意味着目标方法将其参数作为元组处理,因此,可能涉及也可能不涉及某些模式匹配

最新更新