प्रतिबिंब के साथ स्थिर विधि को बुलाओ


111

मेरे पास नाम स्थान में कई स्थिर कक्षाएं हैं 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 में हैं।

जवाबों:


150

MethodInfo.Invoke के लिए प्रलेखन के रूप में , पहला तर्क स्थिर तरीकों के लिए नजरअंदाज कर दिया गया है ताकि आप बस शून्य से गुजर सकें।

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

4
आप कुछ बाध्यकारी झंडे पास करना चाहते हैं GetMethod
डेनियल ए। व्हाइट

2
BindingFlags.Staticआप के बिना पहली जगह में सफलतापूर्वक विधि नहीं मिल सकती है ...
ErikE

1
यदि आप विधि पूर्वज वर्ग में रहते हैं तो आप BindingFlags.FlattenHierarchy जोड़ना चाह सकते हैं।
जे। औवेहंड

20

आप वास्तव में, वास्तव में, वास्तव में केवल एक बार प्रतिनिधि बनाने की कीमत का भुगतान करके अपने कोड को बहुत अधिक अनुकूलित कर सकते हैं (स्थैतिक विधि को कॉल करने के लिए वर्ग को तत्काल करने की कोई आवश्यकता नहीं है)। मैंने कुछ ऐसा ही किया है, और मैं बस एक सहायक वर्ग की मदद से "रन" विधि के लिए एक प्रतिनिधि को कैश करता हूं :-)। यह इस तरह दिख रहा है:

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

यह इस तरह से बहुत तेज है।

यदि आपका विधि हस्ताक्षर एक्शन से भिन्न है, तो आप एक्शन से टाइप-कास्ट और टाइपऑफ़ को किसी भी आवश्यक एक्शन और फ़ंक जेनेरिक प्रकार से बदल सकते हैं, या अपने डेलिगेट की घोषणा कर सकते हैं और इसका उपयोग कर सकते हैं। मेरे स्वयं के कार्यान्वयन में बहुत सी वस्तुओं के लिए फंक का उपयोग होता है:

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

मुझे सादगी पसंद है ...

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

2
किसी भी संभावित अपवाद को निगलना आमतौर पर एक बुरा विचार है।
D स्टेनली

सच। यह आलसी था लेकिन सरल था। मैंने अपना उत्तर सुधार लिया है।
डायनामिकेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.