property functions from example español c# reflection dynamic

functions - list dynamic object c#



Llamar método estático con reflexión (3)

Como indica la documentación para MethodInfo.Invoke , el primer argumento se ignora para los métodos estáticos, por lo que puede pasar el nulo.

foreach (var tempClass in macroClasses) { // using reflection I will be able to run the method as: tempClass.GetMethod("Run").Invoke(null, null); }

Como señala el comentario, es posible que desee asegurarse de que el método sea estático al llamar a GetMethod :

tempClass.GetMethod("Run", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);

Tengo varias clases estáticas en el espacio de nombres mySolution.Macros como

static class Indent{ public static void Run(){ // implementation } // other helper methods }

Entonces mi pregunta es cómo será posible llamar a esos métodos con la ayuda de la reflexión.

Si los métodos NO son estáticos, entonces podría hacer algo como:

var macroClasses = Assembly.GetExecutingAssembly().GetTypes().Where( x => x.Namespace.ToUpper().Contains("MACRO") ); foreach (var tempClass in macroClasses) { var curInsance = Activator.CreateInstance(tempClass); // I know have an instance of a macro and will be able to run it // using reflection I will be able to run the method as: curInsance.GetType().GetMethod("Run").Invoke(curInsance, null); }

Me gustaría mantener mis clases estáticas. ¿Cómo podré hacer algo similar con los métodos estáticos?

En resumen, me gustaría llamar a todos los métodos de ejecución de todas las clases estáticas que están en el espacio de nombres mySolution.Macros.


Prefiero simplicidad ...

private void _InvokeNamespaceClassesStaticMethod(string namespaceName, string methodName, params object[] parameters) { foreach(var _a in AppDomain.CurrentDomain.GetAssemblies()) { foreach(var _t in _a.GetTypes()) { try { if((_t.Namespace == namespaceName) && _t.IsClass) _t.GetMethod(methodName, (BindingFlags.Static | BindingFlags.Public))?.Invoke(null, parameters); } catch { } } } }

Uso...

_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run");

Pero en caso de que esté buscando algo un poco más robusto, incluido el manejo de excepciones ...

private InvokeNamespaceClassStaticMethodResult[] _InvokeNamespaceClassStaticMethod(string namespaceName, string methodName, bool throwExceptions, params object[] parameters) { var results = new List<InvokeNamespaceClassStaticMethodResult>(); foreach(var _a in AppDomain.CurrentDomain.GetAssemblies()) { foreach(var _t in _a.GetTypes()) { if((_t.Namespace == namespaceName) && _t.IsClass) { var method_t = _t.GetMethod(methodName, parameters.Select(_ => _.GetType()).ToArray()); if((method_t != null) && method_t.IsPublic && method_t.IsStatic) { var details_t = new InvokeNamespaceClassStaticMethodResult(); details_t.Namespace = _t.Namespace; details_t.Class = _t.Name; details_t.Method = method_t.Name; try { if(method_t.ReturnType == typeof(void)) { method_t.Invoke(null, parameters); details_t.Void = true; } else { details_t.Return = method_t.Invoke(null, parameters); } } catch(Exception ex) { if(throwExceptions) { throw; } else { details_t.Exception = ex; } } results.Add(details_t); } } } } return results.ToArray(); } private class InvokeNamespaceClassStaticMethodResult { public string Namespace; public string Class; public string Method; public object Return; public bool Void; public Exception Exception; }

El uso es más o menos el mismo ...

_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run", false);


Realmente podría optimizar realmente su código pagando el precio de crear el delegado solo una vez (tampoco hay necesidad de crear una instancia de la clase para llamar a un método estático). He hecho algo muy similar, y simplemente guardo un delegado en el método "Ejecutar" con la ayuda de una clase auxiliar :-). Se parece a esto:

static class Indent{ public static void Run(){ // implementation } // other helper methods } static class MacroRunner { static MacroRunner() { BuildMacroRunnerList(); } static void BuildMacroRunnerList() { macroRunners = System.Reflection.Assembly.GetExecutingAssembly() .GetTypes() .Where(x => x.Namespace.ToUpper().Contains("MACRO")) .Select(t => (Action)Delegate.CreateDelegate( typeof(Action), null, t.GetMethod("Run", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public))) .ToList(); } static List<Action> macroRunners; public static void Run() { foreach(var run in macroRunners) run(); } }

Es MUCHO más rápido de esta manera.

Si la firma de su método es diferente de Action, puede reemplazar los tipos de conversión y typeof de Action por cualquiera de los tipos genéricos Action y Func necesarios, o declarar su Delegate y usarlo. Mi propia implementación usa Func para imprimir objetos bonitos:

static class PrettyPrinter { static PrettyPrinter() { BuildPrettyPrinterList(); } static void BuildPrettyPrinterList() { printers = System.Reflection.Assembly.GetExecutingAssembly() .GetTypes() .Where(x => x.Name.EndsWith("PrettyPrinter")) .Select(t => (Func<object, string>)Delegate.CreateDelegate( typeof(Func<object, string>), null, t.GetMethod("Print", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public))) .ToList(); } static List<Func<object, string>> printers; public static void Print(object obj) { foreach(var printer in printers) print(obj); } }