簡體   English   中英

使用反射調用靜態方法

[英]Call static method with reflection

我在命名空間mySolution.Macros有幾個靜態類,例如

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

所以我的問題是如何在反射的幫助下調用這些方法?

如果方法不是靜態的,那么我可以執行以下操作:

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

我想保持我的課程靜態。 我將如何能夠用靜態方法做類似的事情?

簡而言之,我想從名稱空間 mySolution.Macros 中的所有靜態類中調用所有 Run 方法。

正如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);
}

正如評論指出的那樣,您可能希望在調用GetMethod時確保該方法是靜態的:

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

您可以通過支付只創建一次委托的代價來大量優化代碼(也不需要實例化類來調用靜態方法)。 我做了一些非常相似的事情,我只是在幫助類的幫助下將委托緩存到“運行”方法:-)。 它看起來像這樣:

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

這種方式要快得多。

如果您的方法簽名與 Action 不同,您可以將 Action 中的 type-casts 和 typeof 替換為任何所需的 Action 和 Func 泛型類型,或者聲明您的 Delegate 並使用它。 我自己的實現使用 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);
    }
}

將調用方法的類:

namespace myNamespace
{
    public class myClass
    {
        public static void voidMethodWithoutParameters()
        {
            // code here
        }
        public static string stringReturnMethodWithParameters(string param1, string param2)
        {
            // code here
            return "output";
        }
    }
}

使用反射調用 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());

注意:我不需要實例化 myClass 的對象來使用它的方法,因為我使用的方法是static

優質資源:

我更喜歡簡單...

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 { }
        }
    }
}

用法...

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

但是,如果您正在尋找更強大的東西,包括異常處理......

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

用法幾乎一樣...

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM