Yansıma ile statik yöntemi çağırın


112

Ad alanında birkaç statik sınıfım var mySolution.Macros örneğin

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

Öyleyse sorum, bu yöntemleri yansıtma yardımı ile çağırmanın nasıl mümkün olacağıdır?

Statik OLMAYACAK yöntemler varsa, o zaman şöyle bir şey yapabilirim:

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

Derslerimi statik tutmak isterim. Statik yöntemlerle benzer bir şeyi nasıl yapabilirim?

Kısaca , mySolution.Macros ad alanındaki tüm statik sınıflardan tüm Run yöntemlerini çağırmak istiyorum.

Yanıtlar:


151

As MethodInfo.Invoke belgelerine sadece null adlı geçirebilmeleri için devletler, ilk argüman statik yöntemler için yok sayılır.

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

Yorumun işaret ettiği gibi, yöntemi çağırırken yöntemin statik olduğundan emin olmak isteyebilirsiniz GetMethod:

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

4
bazı bağlama bayraklarını iletmek isteyebilirsiniz GetMethod.
Daniel A. White

2
BindingFlags.StaticSiz olmadan ilk etapta yöntemi başarılı bir şekilde alamayabilirsiniz ...
ErikE

1
Yöntem bir üst sınıfta bulunuyorsa, BindingFlags.FlattenHierarchy eklemek isteyebilirsiniz.
J. Ouwehand

20

Temsilciyi yalnızca bir kez oluşturmanın bedelini ödeyerek kodunuzu gerçekten, gerçekten, gerçekten optimize edebilirsiniz (ayrıca statik bir yöntemi çağırmak için sınıfı başlatmaya gerek yoktur). Çok benzer bir şey yaptım ve bir yardımcıyı bir yardımcı sınıfın yardımıyla "Çalıştır" yöntemine önbelleğe alıyorum :-). Şöyle görünüyor:

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

Bu şekilde ÇOK daha hızlı.

Yöntem imzanız Action'dan farklıysa, Type-casts ve typeof'u Action'dan gerekli Action ve Func jenerik türlerinden herhangi birine değiştirebilirsiniz veya Temsilcinizi bildirip kullanabilirsiniz. Kendi uygulamam nesneleri yazdırmak için Func kullanıyor:

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

0

Sadeliği tercih ederim ...

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

Kullanımı ...

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

Ancak, istisnaların ele alınması da dahil olmak üzere biraz daha sağlam bir şey arıyorsanız ...

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

Kullanım hemen hemen aynıdır ...

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

2
Olası bir istisnayı yutmak genellikle kötü bir fikirdir.
D Stanley

Doğru. Tembel ama basitti. Cevabımı geliştirdim.
dynamichael
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.