使用反射的方法调用的问题问题,怎么解决

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用反射的方法调用的问题问题,怎么解决相关的知识,希望对你有一定的参考价值。

参考技术A Calendar.setTime不是静态方法而是成员方法,要用Calendar的对象进行调用不能用class来调用

使用反射调用静态方法

【中文标题】使用反射调用静态方法【英文标题】:Call static method with reflection 【发布时间】:2012-08-08 03:20:03 【问题描述】:

我在命名空间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 方法。

【问题讨论】:

【参考方案1】:

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

【讨论】:

您可能希望将一些绑定标志传递给GetMethod 如果没有BindingFlags.Static,你可能一开始就无法成功获取方法... 如果方法驻留在祖先类中,您可能需要添加 BindingFlags.FlattenHierarchy。【参考方案2】:

您可以通过只创建一次委托而真正、真正、真正地优化您的代码(也无需实例化类来调用静态方法)。我做了一些非常相似的事情,我只是在帮助类的帮助下将委托缓存到“运行”方法:-)。它看起来像这样:

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 中的类型转换和 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);
    

【讨论】:

【参考方案3】:

将调用方法的类:

namespace myNamespace

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

使用 Reflection 调用 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

大量资源:

How C# Reflection Works MethodBase.Invoke Method

【讨论】:

【参考方案4】:

我更喜欢简单...

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

【讨论】:

吞下任何可能的异常通常是个坏主意。 是的。这很懒惰但很简单。我改进了我的答案。

以上是关于使用反射的方法调用的问题问题,怎么解决的主要内容,如果未能解决你的问题,请参考以下文章

反射 varargs 调用警告

java反射机制可以调用到私有方法,是否就破坏了JAVA的卦装性呢。

使用反射从新实例 (reflect.New) 调用方法

关于用java反射调用一个类里面的方法并执行

如何通过java 反射 调用一个 含有 可变参数的 方法呢 ??

使用反射调用静态方法