.net reflection delegates methodinfo

.net - Crea un delegado de MethodInfo?



reflection delegates (3)

¿Por qué tan complicado?

public static Delegate CreateDelegate(this MethodInfo method) { return Delegate.CreateDelegate ( Expression.GetDelegateType ( method.GetParameters() .Select(p => p.ParameterType) .Concat(new Type[] { method.ReturnType }) .ToArray() ), null, method ); }

[Nota: Prefijo este método "Crear ...". "Para ..." es confusa porque te hace pensar que es una conversión.]

Después de googlear y aterrizar en SO y haber leído esta otra pregunta

¿Es posible construir un delegado correcto desde un MethodInfo si no se conoce el número o los tipos de parámetros en tiempo de compilación?

Más sobre esto: ¿se puede hacer esto de forma elegante sin el uso de Reflection.Emit o type builders?

Esto es bastante malo para mí porque Delegate.CreateDelegate requiere que especifique el tipo de delegado correcto como el primer parámetro o de lo contrario arrojaría excepciones o invocaría un método incorrecto.

Estoy construyendo algunos engranajes ninja y esto ayudaría mucho ... ¡Gracias!

Aquí hay una solución genérica:

/// <summary> /// Builds a Delegate instance from the supplied MethodInfo object and a target to invoke against. /// </summary> public static Delegate ToDelegate(MethodInfo mi, object target) { if (mi == null) throw new ArgumentNullException("mi"); Type delegateType; var typeArgs = mi.GetParameters() .Select(p => p.ParameterType) .ToList(); // builds a delegate type if (mi.ReturnType == typeof(void)) { delegateType = Expression.GetActionType(typeArgs.ToArray()); } else { typeArgs.Add(mi.ReturnType); delegateType = Expression.GetFuncType(typeArgs.ToArray()); } // creates a binded delegate if target is supplied var result = (target == null) ? Delegate.CreateDelegate(delegateType, mi) : Delegate.CreateDelegate(delegateType, target, mi); return result; }

Nota : Estoy construyendo una aplicación de Silverlight que reemplazaría una aplicación javascript construida hace años en la que tengo múltiples interfaces de Javascript que llama al mismo método de Silverlight [ScriptableMember].

Todas esas interfaces JS heredadas necesitan ser compatibles, así como una nueva interfaz para acceder a nuevas características, por lo que algo que configura automáticamente la interfaz JS y "delega" la llamada al método Silverlight correcto ayudaría a acelerar mucho el trabajo.

No puedo publicar el código aquí, así que ese es el resumen.


Para ser honesto, si no conoce el tipo en el momento de la compilación, no hay una gran cantidad de beneficios al crear un Delegate . No desea utilizar DynamicInvoke ; será tan lento como la reflexión. La principal excepción a esto es cuando hay un tipo de delegado al acecho en las sombras, por ejemplo cuando se suscribe a un evento, en cuyo caso EventInfo hace disponible.

Para obtener información, en .NET 3.5 en Expression , hay:

Expression.GetActionType(params Type[] typeArgs); Expression.GetFuncType(params Type[] typeArgs)

Eso podría ayudar en cierta medida:

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; static class Program { static void Main() { DoStuff("Test1"); DoStuff("Test2"); } static void DoStuff(string methodName) { MethodInfo method = typeof(Program).GetMethod(methodName); List<Type> args = new List<Type>( method.GetParameters().Select(p => p.ParameterType)); Type delegateType; if (method.ReturnType == typeof(void)) { delegateType = Expression.GetActionType(args.ToArray()); } else { args.Add(method.ReturnType); delegateType = Expression.GetFuncType(args.ToArray()); } Delegate d = Delegate.CreateDelegate(delegateType, null, method); Console.WriteLine(d); } public static void Test1(int i, DateTime when) { } public static float Test2(string x) { return 0; } }


Si no conoce la cantidad o el tipo de parámetros de antemano, probablemente eso significa que tampoco sabe el tipo de delegado que desea crear.

Si ese es el caso, estás atrapado en el caso absolutamente general.

Sin embargo, para la mayoría de los casos comunes (sin parámetros de ref / out, pocos parámetros suficientes para usar uno de los tipos existentes) podría salirse con la suya con uno de los delegados Func o Action . (.NET 4.0 tiene tipos de Func / Action para un gran número de parámetros, así que realmente solo tendrías que preocuparte por los parámetros out / ref). Si el método tiene un tipo de devolución no nulo usa Func , de lo contrario usa Action . Determine qué tipo usar en función de la cantidad de parámetros, por ejemplo

static readonly Type[] FuncTypes = { typeof(Func), typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), /* etc */ };

Utilice Type.MakeGenericType utilizando los tipos de parámetros y el tipo de devolución para obtener el tipo de delegado correcto, y luego Delegate.CreateDelegate debería funcionar.

No tengo tiempo para buscar una muestra en este momento, pero avíseme si quiere que lo haga más adelante.

Una pregunta: ¿cómo piensa utilizar este delegado? Algo más va a necesitar saber cómo ejecutarlo, seguramente ...