Create an instance of Action<'T> using reflection

China☆狼群 提交于 2019-12-07 05:11:10

问题


How would I create an instance of Action<'T> using reflection? Here's what I have:

let makeAction (typ:Type) (f:'T -> unit) = 
  let actionType = typedefof<Action<_>>.MakeGenericType(typ)
  let converter = FSharpFunc.ToConverter(f)
  Delegate.CreateDelegate(actionType, converter.Method)

which barfs with:

System.ArgumentException: Error binding to target method.
at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throwOnBindFailure)

'T is an interface, which typ implements.


回答1:


I think there are two problems. The first one is that you need to call CreateDelegate overload that takes three arguments. The additional argument specifies the instance on which the method should be invoked.

The second problem is that the Converter<'T, unit> actually compiles as a method that returns Microsoft.FSharp.Core.Unit and not a method that returns void. I'm not sure if there is an easier workaround, but you can define a wrapper that has a method. Members are compiled to look like C#, so the unit type will be compiled as void in that case:

open System

type Wrapper<'T>(f:'T -> unit) =
  member x.Invoke(a:'T) = f a

let makeAction (typ:Type) (f:'T -> unit) = 
  let actionType = typedefof<Action<_>>.MakeGenericType(typ)
  let wrapperType = typedefof<Wrapper<_>>.MakeGenericType(typ)
  let wrapped = Wrapper<_>(f)
  Delegate.CreateDelegate(actionType, wrapped, wrapped.GetType().GetMethod("Invoke"))

makeAction (typeof<int>) (printfn "%d")

EDIT - Did a minor change to make it actually work in your scenario (with interface)



来源:https://stackoverflow.com/questions/6836602/create-an-instance-of-actiont-using-reflection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!