Passsing a value to a method using a custom attribute - c#

I'm trying to understand how can I use custom attributes to call method passing a parameters
[ExecuteMe("hello", "reflection")]
public void M3(string s1, string s2)
{
Console.WriteLine("M3 s1={0} s2={1}", s1, s2);
}
I'm trying to call this method using this code:
static void Main(string[] args)
{
var assembly= Assembly.LoadFrom("MyLibrary.dll");
foreach (var type in assembly.GetTypes())
{
object act = Activator.CreateInstance(type);
var methodInfos = type.GetMethods().Where(m => m.GetCustomAttributes(typeof(ExecuteMe)).Any());
foreach (var mInfo in methodInfos)
{
//Console.WriteLine(mInfo.Name);
var argument = mInfo.GetParameters();
foreach (var a in argument)
{
Console.WriteLine(a);
// a.RawDefaultValue;
mInfo.Invoke(act, new object[]{a});
}
}
if (type.IsClass)
Console.WriteLine(type.FullName);
}
Console.ReadLine();
}
It doesn't work because "a" is a ParameterInfo and invoke want a Object[].
What am I doing wrong and how do I get those values?
this is my attribute:
public class ExecuteMe : Attribute
{
public object[] args;
public ExecuteMe(params object[] _args)
{
this.args = _args;
}
}`

I've rewritten it a little. You never actually accessed the arguments you gave to your attribute.
namespace StackOverflow
{
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public class ExecuteMe : Attribute
{
public object[] Arguments { get; }
public ExecuteMe(params object[] args)
{
this.Arguments = args;
}
}
public class TestSubject
{
[ExecuteMe(5, "Hello")]
[ExecuteMe(7, "World")]
public int Function(int i, string s)
{
Console.WriteLine("Executing TestSubject.Function with parameters {0} and {1}", i, s);
return 42;
}
}
internal static class Program
{
internal static void Main(string[] args)
{
// This could come from another dll, for example
// var assembly = Assembly.LoadFrom("MyLibrary.dll").GetTypes();
var availableTypes = Assembly.GetExecutingAssembly().ExportedTypes;
foreach (var type in availableTypes)
{
foreach (var method in type.GetMethods())
{
foreach (var attribute in method.GetCustomAttributes<ExecuteMe>())
{
var instance = Activator.CreateInstance(type);
method.Invoke(instance, attribute.Arguments);
}
}
}
Console.ReadLine();
}
}
}
This should yield:

To make sure I understand what you're trying to do, if a method has an ExecuteMe attribute, you want to call the method, passing the arguments from the attribute to the method?
I'm going to assume that this is just for experimentation and you already realize that this doesn't guarantee whether the number or type of arguments supplied to the attribute will match the number and type of arguments the method requires. The attribute takes an unlimited number of objects, while the method requires two strings.
The issue that you're seeing is that you're looking at .GetParameters which doesn't tell you anything about the values coming from the attribute. It just describes what the parameters of the method are.
What you need is to get the args property from the attribute and pass those values when you invoke the method.
Just for the sake of illustration I'm going to use a method where the signatures match.
public class ClassWithMethod
{
[ExecuteMe("hello", "reflection")]
public void M3(params object[] args)
{
var strings = args.Where(arg => arg != null).Select(arg => arg.ToString());
Console.WriteLine(string.Join(", ", strings));
}
// Just to verify that we're only invoking methods with the attribute.
public void MethodWithoutAttribute() { }
}
...and in the console app I'm going to read types from the executing assembly just for convenience.
I rearranged a few things but you'll see what's going on:
static void Main(string[] args)
{
var assembly = Assembly.GetExecutingAssembly();
foreach (var type in assembly.GetTypes())
{
var methodInfos = type.GetMethods();
// looking at all the methods, not yet narrowing it down to those
// with the attribute.
foreach (var mInfo in methodInfos)
{
// We don't just want to know if it has the attribute.
// We need to get the attribute.
var executeMeParameter = mInfo.GetCustomAttribute<ExecuteMe>();
// If it's null the method doesn't have the attribute.
// Ignore this method.
if (executeMeParameter == null) continue;
// We don't need to create the instance until we know that we're going
// to invoke the method.
object act = Activator.CreateInstance(type);
// Pass the args property of the attribute (an array of objects)
// as the argument list for the method.
mInfo.Invoke(act, new object[]{executeMeParameter.args});
}
if (type.IsClass)
Console.WriteLine(type.FullName);
}
Console.ReadLine();
}
In this case we're just passing all of the arguments from the attribute. This is the part where it's a little messy. What if args had three string values but the method had a single int parameter?
This part is a little weird. I had to do this because of the params keyword.
mInfo.Invoke(act, new object[]{executeMeParameter.args});
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Another reason why I'm assuming that this is just for experimentation is that if you wanted to use an attribute to determine which method to run and to pass in hard-coded parameters (which itself is something I can't see doing), this would be much easier:
[ExecuteMe]
public void CallM3()
{
M3("Hello", "reflection");
}
public void M3(params object[] args)
{
var strings = args.Where(arg => arg != null).Select(arg => arg.ToString());
Console.WriteLine(string.Join(", ", strings));
}
...and the attribute has no arguments:
public class ExecuteMe : Attribute
{
}
The difference now is that everything is strongly typed and compiles. You don't have to worry about whether the parameters will match up at runtime.

Related

Access static class of dynamic (not known at compile time) type? [duplicate]

I have several static classes in the namespace mySolution.Macros such as
static class Indent{
public static void Run(){
// implementation
}
// other helper methods
}
So my question is how it will be possible to call those methods with the help of reflection?
If the methods where NOT to be static then I could do something like:
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);
}
I will like to keep my classes static. How will I be able to do something similar with static methods?
In short I will like to call all the Run methods from all the static classes that are in the namespace mySolution.Macros.
As the documentation for MethodInfo.Invoke states, the first argument is ignored for static methods so you can just pass null.
foreach (var tempClass in macroClasses)
{
// using reflection I will be able to run the method as:
tempClass.GetMethod("Run").Invoke(null, null);
}
As the comment points out, you may want to ensure the method is static when calling GetMethod:
tempClass.GetMethod("Run", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
You could really, really, really optimize your code a lot by paying the price of creating the delegate only once (there's also no need to instantiate the class to call an static method). I've done something very similar, and I just cache a delegate to the "Run" method with the help of a helper class :-). It looks like this:
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();
}
}
It is MUCH faster this way.
If your method signature is different from Action you could replace the type-casts and typeof from Action to any of the needed Action and Func generic types, or declare your Delegate and use it. My own implementation uses Func to pretty print objects:
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);
}
}
Class that will call the methods:
namespace myNamespace
{
public class myClass
{
public static void voidMethodWithoutParameters()
{
// code here
}
public static string stringReturnMethodWithParameters(string param1, string param2)
{
// code here
return "output";
}
}
}
Calling myClass static methods using Reflection:
var myClassType = Assembly.GetExecutingAssembly().GetType(GetType().Namespace + ".myClass");
// calling my void Method that has no parameters.
myClassType.GetMethod("voidMethodWithoutParameters", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
// calling my string returning Method & passing to it two string parameters.
Object methodOutput = myClassType.GetMethod("stringReturnMethodWithParameters", BindingFlags.Public | BindingFlags.Static).Invoke(null, new object[] { "value1", "value1" });
Console.WriteLine(methodOutput.ToString());
Note: I don't need to instantiate an object of myClass to use it's methods, as the methods I'm using are static.
Great resources:
How C# Reflection Works
MethodBase.Invoke Method
I prefer simplicity...
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 { }
}
}
}
Usage...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run");
But in case you're looking for something a little more robust, including the handling of exceptions...
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;
}
Usage is pretty much the same...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run", false);

Distinguish between a class generic type parameter and method generic type parameter

Given the following example class:
class Foo<T>
{
void Bar<S>(T inputT, S inputS)
{
// Some really magical stuff here!
}
}
If I am reflecting against method Foo<>.Bar<>(...), and examining the parameter types, say:
var argType1 = typeof(Foo<>).GetMethod("Bar").GetParameters()[0].ParameterType;
var argType2 = typeof(Foo<>).GetMethod("Bar").GetParameters()[1].ParameterType;
both argType1 and argType2 look similar:
FullName property is null
Name property is "T" or "S" respectively
IsGenericParameter is true
Is there anything in the parameter type information that allows me to distinguish that the first argument is defined at the type-level, while the second argument is a method-level type parameter?
I suppose, like so:
public static bool IsClassGeneric(Type type)
{
return type.IsGenericParameter && type.DeclaringMethod == null;
}
And in code:
class Program
{
static void Main(string[] args)
{
new Foo<int>().Bar<int>(1,1);
}
class Foo<T>
{
public void Bar<S>(T a, S b)
{
var argType1 = typeof(Foo<>).GetMethod("Bar").GetParameters()[0].ParameterType;
var argType2 = typeof(Foo<>).GetMethod("Bar").GetParameters()[1].ParameterType;
var argType1_res = Ext.IsClassGeneric(argType1);//true
var argType2_res = Ext.IsClassGeneric(argType2);//false
}
}
}

C#: GetMethod by type (generic list)

I have a class with few generic overloaded methods. I am trying to get a specific one by types of its parameters. It's relatively easy to do, when I stick to the first two (with arguments of type int and string). But no matter what I do I cannot get my program to notice the third one, intended for generic list. Do I use a wrong Type argument? If so what is a correct way?
/* rest of code */
static void Main(string[] args) {
MethodInfo method =
typeof(c).GetMethod("m", new Type[] { typeof(int) });
Console.WriteLine(method);
method =
typeof(c).GetMethod("m", new Type[] { typeof(String) });
Console.WriteLine(method);
method =
typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<>) });
Console.WriteLine(method);
Console.ReadKey();
}
}
static class c
{
public static void m<T>(int i)
{
}
public static void m<T>(String s)
{
}
public static void m<T>(IEnumerable<T> Ls)
{
}
}
Short version: typeof(IEnumerable<>) is not the same as typeof(IEnumerable<T>) (for some T).
Longer version: there is no method void c.m(IEnumerable<> Ls), only overloads where the generic parameter will be some specific – existing at run time – type where the jitter has needed to create the method due to some code referencing that instantiation of the generic method.
Add a call, in your test code, to some instance of the generic method and then do a GetMethod for that instance.
Consider the following:
using System.Collections.Generic;
using System.Linq;
using static System.Console;
class Methods {
public static void M(int x) {
// no-op
}
public static void M<T>(IEnumerable<T> x) {
// no-op
}
}
class Program {
static void Main(string[] args) {
Methods.M(0);
Methods.M(new[] { "a", "b" });
ShowAllM();
}
public static void ShowAllM() {
var tm = typeof(Methods);
foreach (var mi in tm.GetMethods().Where(m => m.Name == "M"))
{
WriteLine(mi.Name);
foreach (var p in mi.GetParameters())
{
WriteLine($"\t{p.ParameterType.Name}");
}
}
}
}
which produces the output:
M
Int32
M
IEnumerable`1
Note there is only one result from the generic overload. If a call to M<char>(…) is added to Main then the output is the same.
For reflection there is just one method, are its argument reflects its "open generic" nature, but that isn't quite the same as being callable with an open generic type (eg. IEnumerable<>) as open types are not instantiatable.
(I've fudged much of the technical details here. It is instruictive to look at the difference in a debugger between typeof(IEnumerable<>) and typeof(IEnumerable<int>).)
The third method has a signature of m<T>(IEnumerable<T>) but your example shows an attempt to find a method with a signature m(IEnumerable<>).
The difference between the typeof(IEnumerable<T>) and typeof(IEnumerable<>) is the the former is a generic type and the second is a generic type definition and these are not the same thing. A generic type is determined from both the generic type definition and the generic type arguments.
With that in mind you would want to use:
method =
typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<MyType>) });
and substitute the type of enumerable that you will be passing into the method.
On the other hand if you don't know the type of enumerable up front you could get the generic method definition and make the useable generic method when you need it:
methodDef =
typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<object>) }).GetGenericMethodDefinition();
method = methodDef.MakeGenericMethod(new Type[] { typeof(MyType) });
If you remove generic defenitions from int and string methods:
public static void m(int i)
{
}
public static void m(String s)
{
}
public static void m<T>(IEnumerable<T> Ls)
{
}
And use following lines to get needed generic method:
method = typeof(c).GetMethods().FirstOrDefault(m => m.IsGenericMethod &&
m.GetParameters()[0].ParameterType.GetGenericTypeDefinition()
== typeof(IEnumerable<>));
This will do the trick
/// <summary>
/// Will fetch first occurence of IEnumerable<T> method and generate new generic method
/// <para/>
/// that corresponds to Document type
/// </summary>
/// <param name="Document"></param>
/// <param name="MethodName"></param>
/// <returns></returns>
public static MethodInfo GetAppropriateCollectionGenericMethod(object SourceClass, dynamic Document, string MethodName)
{
//get all public methods
var publicMethods = SourceClass.GetType().GetMethods().Where(x => x.Name == MethodName && x.IsGenericMethod);
//filter out only useful methods
foreach (var goodMethod in publicMethods)
{
var methodParams = goodMethod.GetParameters();
var firstParameterType = methodParams[0].ParameterType;
//methods that has arguments like Ienumerable<T>, RepeatedField<T> and so on
var hasNested = firstParameterType.GenericTypeArguments.Length > 0;
if (hasNested == true)
{
//if we found first method with that name that has as parameter an IEnumerable<T> we are ok
var genericTypeDef = firstParameterType.GetGenericTypeDefinition();
if (genericTypeDef == typeof(IEnumerable<>))
{
//Recover current document type, even if it's a list of such types
Type documentType = GetDocumentNestedType(Document);
//simply create a generic method based on Document inner Type
return goodMethod.MakeGenericMethod(documentType);
}
}
}
return null;
}
You will need this, in order to avoid errors:
var hasNested = firstParameterType.GenericTypeArguments.Length > 0;
This will fetch first occurency of:
public static void m<T>(IEnumerable<T> Ls)
{
}
and will generate a method that you can use like that:
var localMethod = GenericReflectionHelper.GetAppropriateCollectionGenericMethod(this, Document, nameof(Insert));
//we are relying on implicit casting
localMethod.Invoke(this, new object[] { Document });
Full sample:
public void Insert<T>(T Document)
{
//Valid for Lists and Repeated Fields
if (Document is IEnumerable)
{
MethodInfo localMethod;
var tuple = Tuple.Create(Document.GetType(), nameof(Insert));
if (CachedMethodsRedirection.ContainsKey(tuple) == true)
{
localMethod = CachedMethodsRedirection[tuple];
}
else
{
localMethod = GenericReflectionHelper.GetAppropriateCollectionGenericMethod(this, Document, nameof(Insert));
CachedMethodsRedirection.Add(tuple, localMethod);
}
//we are relying on implicit casting
localMethod.Invoke(this, new object[] { Document });
}
else
{
DocumentSession.GetCollection<T>().Insert(Document);
}
}
public void Insert<T>(IEnumerable<T> Document)
{
DocumentSession.GetCollection<T>().Insert(Document);
}

Accessing a delegate via reflection declared outside of any class?

I am trying a demo for reflection. The assembly I want to reflect in this class goes something like this
namespace DelegatesSampleApplication
{
delegate bool IsPromotable (Employee employee); // Declaration Syntax is similar to that of a method's
class Program
{
public static void Main(string[] args)
{
//code goes here
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public int Salary { get; set; }
public int Experience { get; set; }
public void PromoteEmployees(List<Employee> employeeList, IsPromotable isPromotableObj)
{
/*foreach (Employee employee in employeeList)
{
if (employee.Experience >= 5 && employee.Salary >= 10000) //That's a hard-coded logic that you have developed as a Framework Developer which makes the class itself not reusable
{
Console.WriteLine(" {0} will be promoted in the next R.P. Cycle ", employee.EmployeeName);
}
}
Console.ReadKey();*/
foreach (Employee employee in employeeList)
{
if (isPromotableObj(employee))
{
Console.WriteLine(" {0} will be promoted in the next R.P. Cycle ", employee.EmployeeName);
}
}
Console.ReadKey();
}
}
}
Now the problem I am facing is, I am trying to read from this assembly in my program and trying to invoke the delegate which takes in a class instance as a parameter.
What I am doing is something like this in a different class altogether
namespace ReflectionSample
{
delegate bool empIsPromotable (Object obj);
class Program
{
static void Main(string[] args)
{
Console.WriteLine("***************Loading External assembly*************");
Assembly assembly = Assembly.LoadFrom(#"C:\Users\Chiranjib\Documents\visual studio 2012\Projects\DelegatesSampleApplication\DelegatesSampleApplication\bin\Debug\DelegatesSampleApplication.exe");
Type employeeType = assembly.GetType("DelegatesSampleApplication.Employee"); //Gets the System.Type object for the Employee Class from the just loaded assembly with all it's dependencies
Console.WriteLine("***************Loading External assembly properties*************");
//Setting properties here
Console.WriteLine("***************Creating an array list that will hold these employee instances***************");
List<Object> employeeInstanceList = new List<object>();
employeeInstanceList.Add(employeeInstance);
employeeInstanceList.Add(employeeInstance2);
Console.WriteLine("***************Invoking External assembly methods*************");
var args = new Object[] {
new List<employeeType>(),
(((employeeInstance) => { return true; }))
};
Console.ReadKey();
}
}
}
This throws error. Saying employeeType missing an assembly reference. Also I cannot convert a lambda expression into an object. I cannot directly type cast to (IsPromotable) right ? I am using reflection. So I am supposed not to have a direct access.
How would I be able to access the delegate via reflection ?
Please help me through. Thanks in advance.
IsPromotable is not invokeable, it's simply a delegate definition. Think of it like an interface. It just tells you what the method takes and returns, but does not actually do anything.
You can call PromoteEmployees like this:
PromoteEmployees(new List<Employee>, (employee) => { return employee.Name == "Rob"; });
Any method which matches the signature of IsPromotable is a valid parameter to the method (ie, any method that takes an Employee and returns a bool). Could you elaborate a bit more on what you're trying to do, exactly?
If you just want a list of delegates, you can do this:
GetType().Assembly.GetTypes().Where(t => t.IsSubClassOf(typeof(BaseDelegate)));
Note; this will only return the delegates in your current assembly. You might want to change it to:
typeof(Employee).GetTypes().Assembly.Where(t => t.IsSubClassOf(typeof(BaseDelegate)));
To get all methods in an assembly which are castable to IsPromotable, you can do this:
var delegateMethod = typeof(IsPromotable).GetMethod("Invoke");
var #params = delegateMethod.GetParameters();
var returnType = delegateMethod.ReturnType;
var matchingMethods = typeof(IsPromotable)
.Assembly
.GetTypes()
.SelectMany(t => t.GetMethods())
.Where(m => {
if (m.ReturnType != returnType)
return false;
var currParams = m.GetParameters();
if (currParams.Length != #params.Length)
return false;
for(var i = 0; i < currParams.Length;i++)
if (currParams[i] != #params[i])
return false;
return true;
});
To invoke the method with reflection, you can do this:
var args = new Object[] {
new List<Employee>(),
((IsPromotable)((emp) => { return true; }))
};
var value = employeeType.InvokeMember("PromoteEmployees", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, employeeInstance, args);
Or, you can just pass it a regular method:
var args = new Object[] {
new List<Employee>(),
((IsPromotable)Test)
};
var value = employeeType.InvokeMember("PromoteEmployees", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, employeeInstance, args);
With the method:
private bool Test(Employee emp)
{
return false;
}

Call static method with reflection

I have several static classes in the namespace mySolution.Macros such as
static class Indent{
public static void Run(){
// implementation
}
// other helper methods
}
So my question is how it will be possible to call those methods with the help of reflection?
If the methods where NOT to be static then I could do something like:
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);
}
I will like to keep my classes static. How will I be able to do something similar with static methods?
In short I will like to call all the Run methods from all the static classes that are in the namespace mySolution.Macros.
As the documentation for MethodInfo.Invoke states, the first argument is ignored for static methods so you can just pass null.
foreach (var tempClass in macroClasses)
{
// using reflection I will be able to run the method as:
tempClass.GetMethod("Run").Invoke(null, null);
}
As the comment points out, you may want to ensure the method is static when calling GetMethod:
tempClass.GetMethod("Run", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
You could really, really, really optimize your code a lot by paying the price of creating the delegate only once (there's also no need to instantiate the class to call an static method). I've done something very similar, and I just cache a delegate to the "Run" method with the help of a helper class :-). It looks like this:
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();
}
}
It is MUCH faster this way.
If your method signature is different from Action you could replace the type-casts and typeof from Action to any of the needed Action and Func generic types, or declare your Delegate and use it. My own implementation uses Func to pretty print objects:
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);
}
}
Class that will call the methods:
namespace myNamespace
{
public class myClass
{
public static void voidMethodWithoutParameters()
{
// code here
}
public static string stringReturnMethodWithParameters(string param1, string param2)
{
// code here
return "output";
}
}
}
Calling myClass static methods using Reflection:
var myClassType = Assembly.GetExecutingAssembly().GetType(GetType().Namespace + ".myClass");
// calling my void Method that has no parameters.
myClassType.GetMethod("voidMethodWithoutParameters", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
// calling my string returning Method & passing to it two string parameters.
Object methodOutput = myClassType.GetMethod("stringReturnMethodWithParameters", BindingFlags.Public | BindingFlags.Static).Invoke(null, new object[] { "value1", "value1" });
Console.WriteLine(methodOutput.ToString());
Note: I don't need to instantiate an object of myClass to use it's methods, as the methods I'm using are static.
Great resources:
How C# Reflection Works
MethodBase.Invoke Method
I prefer simplicity...
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 { }
}
}
}
Usage...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run");
But in case you're looking for something a little more robust, including the handling of exceptions...
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;
}
Usage is pretty much the same...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run", false);

Categories