FSharp中的动态函数调用

时间:2017-02-07 11:46:25

标签: function dynamic f#

是否有可能采用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

看来您目前不得不退回到标准反射(例如:calling a F# function by name),但这种方法似乎非常脆弱。主要是因为它没有真正保证它有效,你必须知道幕后发生了什么。

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

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

1 个答案:

答案 0 :(得分:0)

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)

对于params,您必须将它们作为Tuple传递给

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