2011-07-26 7 views
5

¿Cómo crearía una instancia de Action<'T> utilizando la reflexión? Aquí es lo que tengo:Cree una instancia de la acción <'T> utilizando la reflexión

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

el que vomita con:

System.ArgumentException: error unirse a secuencias diana método.
en System.Delegate.CreateDelegate (tipo tipo, método MethodInfo, Boolean throwOnBindFailure)

'T es una interfaz, que typ implementos.

+0

¿Hay alguna razón específica por la que quiera hacer esto usando la reflexión? Como esto se puede hacer tan simple como: 'let makeAction (f: 'a -> unit) = new Action <'a> (f)' – Ankur

+0

@Ankur: Sí, porque no sé ''a' (en tu ejemplo) en tiempo de compilación. – Daniel

+0

No estoy seguro de si te entiendo correctamente, pero el ''a' aquí es igual que'' T' en tu código, es decir, un tipo genérico que se resuelve dependiendo del valor 'f' pasado. Necesita un tipo de acción que ajuste la función 'f' pasada ¿verdad? – Ankur

Respuesta

3

Creo que hay dos problemas. El primero es que debe llamar al CreateDelegate sobrecarga que toma tres argumentos. El argumento adicional especifica la instancia en la que se debe invocar el método.

El segundo problema es que el Converter<'T, unit> realmente compila como un método que devuelve Microsoft.FSharp.Core.Unit y no un método que devuelve void. No estoy seguro de si hay una solución más fácil, pero puede definir un contenedor que tenga un método. Los miembros son compilados para parecerse a C#, por lo que el tipo de unidad se compilará como void en ese caso:

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

EDITAR - Hicimos un pequeño cambio para que sea realmente funciona en su escenario (con interfaz)

+0

Impresionante. ¡Gracias! Solo estaba creando el 'Convertidor' para obtener' MethodInfo'. No estaba seguro de qué otra manera obtenerlo de una función F #. – Daniel

+0

@Daniel - Si tiene una función 'f', también puede usar' f.GetType(). GetMethod ("Invoke") ', pero eso le da un método que devuelve' unidad', por lo que no funcionará en este caso. –

+0

Sí, lo intenté primero e hice el mismo descubrimiento. – Daniel

Cuestiones relacionadas