เรียกวิธีการคงที่ด้วยการสะท้อน


112

ฉันมีคลาสคงที่หลายตัวในเนมสเปซ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);
}

ฉันต้องการให้ชั้นเรียนคงที่ ฉันจะทำสิ่งที่คล้ายกันด้วยวิธีการคงที่ได้อย่างไร

ในระยะสั้นฉันต้องการเรียกใช้เมธอด Run ทั้งหมดจากคลาสสแตติกทั้งหมดที่อยู่ในเนมสเปซ mySolution.Macros

คำตอบ:


151

ในฐานะที่เป็นเอกสารสำหรับ 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);

4
GetMethodคุณอาจต้องการที่จะผ่านธงผูกพันบางอย่างเพื่อ
Daniel

2
หากไม่มีBindingFlags.Staticคุณอาจไม่ได้รับวิธีการนี้ในตอนแรก ...
ErikE

1
คุณอาจต้องการเพิ่ม BindingFlags.FlattenHierarchy ถ้าเมธอดอยู่ในคลาสบรรพบุรุษ
J. Ouwehand

20

คุณสามารถเพิ่มประสิทธิภาพโค้ดของคุณได้มากจริงๆโดยจ่ายราคาในการสร้างผู้รับมอบสิทธิ์เพียงครั้งเดียว (ไม่จำเป็นต้องสร้างอินสแตนซ์คลาสเพื่อเรียกเมธอดแบบคงที่) ฉันได้ทำบางสิ่งที่คล้ายกันมากและฉันก็แคชตัวแทนของเมธอด "Run" ด้วยความช่วยเหลือของคลาสตัวช่วย :-) ดูเหมือนว่า:

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 คุณสามารถแทนที่ type-casts และ typeof จาก Action เป็น 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);
    }
}

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 Stanley

จริง. มันขี้เกียจ แต่เรียบง่าย ฉันปรับปรุงคำตอบของฉันแล้ว
dynamichael
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.