Создайте экземпляр Action <'T>, используя отражение - PullRequest
5 голосов
/ 27 июля 2011

Как мне создать экземпляр Action<'T>, используя отражение? Вот что у меня есть:

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

, с чем:

System.ArgumentException: ошибка привязки к целевому методу.
в System.Delegate.CreateDelegate (тип Type, метод MethodInfo, логический throwOnBindFailure)

'T - это интерфейс, который реализует typ.

1 Ответ

4 голосов
/ 27 июля 2011

Я думаю, что есть две проблемы. Во-первых, вам нужно вызвать перегрузку CreateDelegate, которая принимает три аргумента. Дополнительный аргумент указывает экземпляр, для которого должен быть вызван метод.

Вторая проблема заключается в том, что Converter<'T, unit> фактически компилируется как метод, который возвращает Microsoft.FSharp.Core.Unit, а не как метод, который возвращает void. Я не уверен, есть ли более простой обходной путь, но вы можете определить оболочку, у которой есть метод. Члены компилируются, чтобы выглядеть как C #, поэтому тип модуля будет скомпилирован как void в этом случае:

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")

РЕДАКТИРОВАТЬ - Внесены незначительные изменения, чтобы он действительно работал в вашем сценарии (с интерфейсом)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...