[TestAttribute(Name = "Test")]
public void Test()
{
Test2();
}
public viod Test2()
{
Console.Write(TestAttribute.Name);
}
As shown above, is it possible to get the information of the attribute of Test when called in Test2?
Preferable without stacktrace.
Instead of using stacktrace you could use MethodBase.GetCurrentMethod() and pass it to your secondary method.
[TestAttribute(Name = "Test")]
public void Test()
{
Test2(MethodBase.GetCurrentMethod());
}
public viod Test2(MethodBase sender)
{
var attr = sender.GetCustomAttributes(typeof(TestAttribute), false).FirstOrDefault();
if(attr != null)
{
TestAttribute ta = attr as TestAttribute;
Console.WriteLine(ta.Name);
}
}
I wouldn't know how to get to the caller without stacktrace in your case:
[TestAttribute(Name = "Test")]
static void Test() {
Test2();
}
static void Test2() {
StackTrace st = new StackTrace(1);
var attributes = st.GetFrame(0).GetMethod().GetCustomAttributes(typeof(TestAttribute), false);
TestAttribute testAttribute = attributes[0] as TestAttribute;
if (testAttribute != null) {
Console.Write(testAttribute.Name);
}
}
An alternative is to explicitly pass the method information to the function:
[TestAttribute(Name = "Test")]
void TestMethod() {
MethodInfo thisMethod = GetType().GetMethod("TestMethod", BindingFlags.Instance | BindingFlags.NonPublic);
Test3(thisMethod);
}
static void Test3(MethodInfo caller) {
var attributes = caller.GetCustomAttributes(typeof(TestAttribute), false);
TestAttribute testAttribute = attributes[0] as TestAttribute;
if (testAttribute != null) {
Console.Write(testAttribute.Name);
}
}
By the way, this does not really look like something you want to do with reflection; I think that in this case the way to go is just this :)
void Test() {
Test2(name);
}
void Test2(string name) {
Console.Write(name);
}
Related
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);
Good day!
My purpose is to implement class which will allow us subscribe and unsubscribe objects to(from) events. Here is the code of my class.
public static class EventSubscriber
{
public static void AddEventHandler(EventInfo eventInfo, object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.AddEventHandler(item, handler);
}
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.RemoveEventHandler(item, handler);
}
private static ParameterExpression[] GetParameters(EventInfo eventInfo)
{
return eventInfo.EventHandlerType
.GetMethod("Invoke")
.GetParameters()
.Select(parameter => Expression.Parameter(parameter.ParameterType))
.ToArray();
}
private static Delegate GetHandler(EventInfo eventInfo,
Action action, ParameterExpression[] parameters)
{
return Expression.Lambda(
eventInfo.EventHandlerType,
Expression.Call(Expression.Constant(action),
"Invoke", Type.EmptyTypes), parameters)
.Compile();
}
}
As you can see here are 2 public methods which actually subscribe and unsubscribe objects to(from) event. And here is the sample how I test it
class Program
{
static void Main()
{
Test test = new Test();
test.SubscribeTimer();
while (true)
{
if(test.a == 10)
{
break;
}
}
test.UnsubscribeTimer();
while (true)
{
}
}
}
class Test
{
System.Timers.Timer timer;
public int a = 0;
public Test()
{
timer = new System.Timers.Timer(1000);
timer.Start();
}
public void SubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerNotElapsed);
}
public void UnsubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerNotElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerElapsed);
}
public void TimerElapsed()
{
Console.WriteLine("timer elapsed");
a++;
}
public void TimerNotElapsed()
{
Console.WriteLine("timer not elapsed");
a++;
}
}
The expected behaviour of sample is that on the begining we will see the message "timer elapsed" every second, after 10-th second we should see only "timer not elapsed" and we do, but we still see "timer elapsed" too. This means that AddEventHandler method works, but RemoveEventHandler method doesn't.
I would be very happy if you will help me. Thanks in advance.
Had to stitch a bunch of sources together to get what I needed which was a one-stop extension method (that could be easily modified if we switched component vendors) to simply clear all existing Event Handlers on an Event we did not control.
Usage is simple:
thirdPartyControlInstance.ClearEventHandlers(nameof(ThirdPartyControlType.ToolClick));
Here is the code, any suggestions to make it more robust/efficient/cleaner are welcome:
public static class EventExtensions
{
public static void ClearEventHandlers(this object obj, string eventName)
{
if (obj == null)
{
return;
}
var objType = obj.GetType();
var eventInfo = objType.GetEvent(eventName);
if (eventInfo == null)
{
return;
}
var isEventProperty = false;
var type = objType;
FieldInfo eventFieldInfo = null;
while (type != null)
{
/* Find events defined as field */
eventFieldInfo = type.GetField(eventName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (eventFieldInfo != null && (eventFieldInfo.FieldType == typeof(MulticastDelegate) || eventFieldInfo.FieldType.IsSubclassOf(typeof(MulticastDelegate))))
{
break;
}
/* Find events defined as property { add; remove; } */
eventFieldInfo = type.GetField("EVENT_" + eventName.ToUpper(), BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
if (eventFieldInfo != null)
{
isEventProperty = true;
break;
}
type = type.BaseType;
}
if (eventFieldInfo == null)
{
return;
}
if (isEventProperty)
{
// Default Events Collection Type
RemoveHandler<EventHandlerList>(obj, eventFieldInfo);
// Infragistics Events Collection Type
RemoveHandler<EventHandlerDictionary>(obj, eventFieldInfo);
return;
}
if (!(eventFieldInfo.GetValue(obj) is Delegate eventDelegate))
{
return;
}
// Remove Field based event handlers
foreach (var d in eventDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(obj, d);
}
}
private static void RemoveHandler<T>(object obj, FieldInfo eventFieldInfo)
{
var objType = obj.GetType();
var eventPropertyValue = eventFieldInfo.GetValue(obj);
if (eventPropertyValue == null)
{
return;
}
var propertyInfo = objType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(p => p.Name == "Events" && p.PropertyType == typeof(T));
if (propertyInfo == null)
{
return;
}
var eventList = propertyInfo?.GetValue(obj, null);
switch (eventList) {
case null:
return;
case EventHandlerDictionary typedEventList:
typedEventList.RemoveHandler(eventPropertyValue, typedEventList[eventPropertyValue]);
break;
}
}
}
Hope this helps someone!
I think it's because you are creating a new handler each time: (which doesn't match the previous handler, so can't be removed from the invocation list)
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters); // <--
eventInfo.RemoveEventHandler(item, handler);
}
Why are you wrapping the Action? To lose the parameters? It is not possible to add/remove the eventInfo.RemoveEventHandler(item, action); because of the parameters. If you want to remove a newly generated handler, you should return that handler when you want to remove it.
public static Delegate AddEventHandler(EventInfo eventInfo, object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.AddEventHandler(item, handler);
return handler;
}
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Delegate handler)
{
eventInfo.RemoveEventHandler(item, handler);
}
var handler = EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, handler);
I have a base class:
abstract class ClassPlugin
{
public ClassPlugin(eGuiType _guyType)
{
GuiType = _guyType;
}
public eGuiType GuiType;
}
then I have various derived classes, one of them being this
class ClassIO : ClassPlugin
{
public ClassIO(eGuiType _guyType, eIoType _ioType) : base(_guyType)
{
GuyType = _guyType;
ioType = _ioType;
}
eIoType ioType;
public enum eIoType { UKNOWN, READ, WRITE, MONITOR }
public override void Action(){...}
}
so now when launching my application I use that code:
public static List<Type> FindAllDerivedTypes<T>()
{
return FindAllDerivedTypes<T>(Assembly.GetAssembly(typeof(T)));
}
public static List<Type> FindAllDerivedTypes<T>(Assembly assembly)
{
var derivedType = typeof(T);
return assembly
.GetTypes()
.Where(t =>
t != derivedType && derivedType.IsAssignableFrom(t)).ToList();
}
finally I use it with
var output = FindAllDerivedTypes<ClassPlugin>();
foreach (var classType in output)
{
if (classType.Name == "ClassIO")
{
foreach (var item in classType.GetMembers())
{
????
}
}
}
so what I need to do is [pseudocode to be put where the ??? are]
bool IsMonitorType = false;
if(item.member == eIoType && item.Value == eIoType.MONITOR)
{
IsMonitorType == true;
break;
}
and then
if(item.member.Name "Action")
{
item.member.execute();
}
so in short I have to:
identify the instance type throgh eIoType
if ioType == MONITOR execute its Action routine
Thank you for any help
if (classType.Name == "ClassIO")
{
//You can get the field like this
var fieldInfo = classType.GetField("ioType",BindingFlags.NonPublic|BindingFlags.Instance);
if (fieldInfo != null)
{
//...
}
//You can get the method like this
var methodInfo = classType.GetMethod("Action");
if (methodInfo != null)
{
//create an instance of ClassIO
var classInstance = Activator.CreateInstance(classType, new eGuiType(), ClassIO.eIoType.MONITOR);
//Execute Action method
methodInfo.Invoke(classInstance, null);
}
}
I'm not sure how you think you're going to check the value of eIoType though, you're just dealing with the Type ClassIO here not an instance of it
I've read some stuff about the ExpandoObject, and that I can expand it with properties,fields,methods.
//that's how to add a property to an ExpandoObject.
dynamic x = new ExpandoObject();
x.NewProp = string.Empty;
But sometimes, it could be handy to add a property with some "extra-code".
class sample
{
// a sample field.
public string sampleString{get;set}
// a sample property with some "extra code"
private string s;
public string sampleExtraString
{
get{return s;}
set{s=value;Console.WriteLine(s);}
}
}
Now my question is, how can I add a property to the ExpandoObject that will execute my Console.WriteLine(s); for example on set.
ExpandoObject implements INotifyPropertyChanged, as explained here
(at the bottom of the page)
((INotifyPropertyChanged)x).PropertyChanged +=
new PropertyChangedEventHandler(Expando_PropertyChanged);
x.NewProp = string.Empty;
private static void Expando_PropertyChanged(object sender,
PropertyChangedEventArgs e)
{
Console.WriteLine("{0} has changed.", e.PropertyName);
}
I think a better approach would be using DynamicObject which you can intercept the calls for methods and properties.
This is a simple example, a more robust one would not use reflection to perform set/get operations on the property but rather using reflection.Emit or any compiled operation strategy.
public class Sample
{
public string SampleExtraString { get; set; }
}
public class Factory
{
public class ExtraPropertyObject<T> : DynamicObject
{
private readonly T instance = default(T);
private readonly Type instanceType = null;
public ExtraPropertyObject(T instance) {
this.instance = instance;
instanceType = instance.GetType();
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
PropertyInfo prop = null;
if (binder.Name.Equals("SampleExtraString")) {
Console.WriteLine(value);
}
prop = instanceType.GetProperty(binder.Name);
if (prop != null) {
try {
prop.SetValue(instance, value);
return true;
}
catch (Exception ex) {
}
}
return false;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
var prop = instanceType.GetProperty(binder.Name);
if (prop != null) {
try {
result = prop.GetValue(instance);
return true;
}
catch (Exception ex) {
}
}
result = null;
return false;
}
}
public static dynamic CreateInstance<TInstance>() where TInstance : class, new() {
return new ExtraPropertyObject<TInstance>(new TInstance());
}
public static dynamic CreateInstance<TInstance>(TInstance instance) {
return new ExtraPropertyObject<TInstance>(instance);
}
}
class Program
{
static void Main(string[] args) {
var instance = Factory.CreateInstance<Sample>();
instance.SampleExtraString = "value";
Console.WriteLine("Get Operation: {0}", instance.SampleExtraString);
}
}
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);