it-swarm.com.de

Rufen Sie eine statische Methode mit Reflektion auf

Ich habe mehrere statische Klassen im Namespace mySolution.Macros, wie zum Beispiel 

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

Meine Frage ist also, wie es möglich sein wird, diese Methoden mit Hilfe der Reflexion aufzurufen.

Wenn die Methoden NICHT statisch sein sollten, könnte ich Folgendes tun:

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

Ich möchte meinen Unterricht gerne statisch halten. Wie kann ich mit statischen Methoden etwas Ähnliches machen?

Kurz gesagt Ich möchte gerne alle Run-Methoden aus allen statischen Klassen aufrufen, die sich im Namensraum mySolution.Macros befinden.

89
Tono Nam

Als Dokumentation für MethodInfo.Invoke States wird das erste Argument für statische Methoden ignoriert, sodass Sie einfach null übergeben können.

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

Wie aus dem Kommentar hervorgeht, sollten Sie beim Aufruf von GetMethod sicherstellen, dass die Methode statisch ist:

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

Sie können Ihren Code wirklich, wirklich, wirklich optimieren, indem Sie den Preis für das Erstellen des Delegaten nur einmal zahlen (es ist auch nicht erforderlich, die Klasse zu instanziieren, um eine statische Methode aufzurufen). Ich habe etwas sehr ähnliches getan und ich zwinge einen Delegaten mithilfe einer Hilfsklasse in die Methode "Run". Es sieht aus wie das:

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 ist viel schneller auf diese Weise. 

Wenn sich Ihre Methodensignatur von Action unterscheidet, können Sie die Typumwandlungen und den Typeof von Action durch einen beliebigen der generischen Action- und Func-Typen ersetzen oder Ihren Delegierten deklarieren und verwenden. Meine eigene Implementierung verwendet Func, um Objekte hübsch zu drucken:

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

Ich bevorzuge Einfachheit ...

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

Verwendungszweck...

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

Falls Sie jedoch etwas robusteres suchen, einschließlich der Behandlung von Ausnahmen ...

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

Die Nutzung ist ziemlich gleich ...

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