简体   繁体   English

使用反射调用静态方法

[英]Call static method with reflection

I have several static classes in the namespace mySolution.Macros such as我在命名空间mySolution.Macros有几个静态类,例如

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.简而言之,我想从名称空间 mySolution.Macros 中的所有静态类中调用所有 Run 方法。

As the documentation for MethodInfo.Invoke states, the first argument is ignored for static methods so you can just pass null.正如MethodInfo.Invoke文档所述,静态方法的第一个参数将被忽略,因此您可以只传递 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 :正如评论指出的那样,您可能希望在调用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.如果您的方法签名与 Action 不同,您可以将 Action 中的 type-casts 和 typeof 替换为任何所需的 Action 和 Func 泛型类型,或者声明您的 Delegate 并使用它。 My own implementation uses Func to pretty print objects:我自己的实现使用 Func 来漂亮地打印对象:

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 :使用反射调用 myClass 静态方法:

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 .注意:我不需要实例化 myClass 的对象来使用它的方法,因为我使用的方法是static

Great resources:优质资源:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM