首页 文章

反思:如何使用参数调用方法

提问于
浏览
170

我试图通过参数反射调用方法,我得到:

对象与目标类型不匹配

如果我调用没有参数的方法,它可以正常工作 . 基于以下代码,如果我调用方法 Test("TestNoParameters") ,它工作正常 . 但是,如果我调用 Test("Run") ,我会得到一个例外 . 我的代码有问题吗?

我最初的目的是传递一系列对象,例如 public void Run(object[] options) 但这不起作用,我尝试了一些更简单的例子,例如字符串没有成功 .

// Assembly1.dll
namespace TestAssembly
{
    public class Main
    {
        public void Run(string parameters)
        { 
            // Do something... 
        }
        public void TestNoParameters()
        {
            // Do something... 
        }
    }
}

// Executing Assembly.exe
public class TestReflection
{
    public void Test(string methodName)
    {
        Assembly assembly = Assembly.LoadFile("...Assembly1.dll");
        Type type = assembly.GetType("TestAssembly.Main");

        if (type != null)
        {
            MethodInfo methodInfo = type.GetMethod(methodName);

            if (methodInfo != null)
            {
                object result = null;
                ParameterInfo[] parameters = methodInfo.GetParameters();
                object classInstance = Activator.CreateInstance(type, null);

                if (parameters.Length == 0)
                {
                    // This works fine
                    result = methodInfo.Invoke(classInstance, null);
                }
                else
                {
                    object[] parametersArray = new object[] { "Hello" };

                    // The invoke does NOT work;
                    // it throws "Object does not match target type"             
                    result = methodInfo.Invoke(methodInfo, parametersArray);
                }
            }
        }
    }
}

7 回答

  • 8

    将“methodInfo”更改为“classInstance”,就像使用null参数数组的调用一样 .

    result = methodInfo.Invoke(classInstance, parametersArray);
    
  • 26

    你有一个错误

    result = methodInfo.Invoke(methodInfo, parametersArray);
    

    它应该是

    result = methodInfo.Invoke(classInstance, parametersArray);
    
  • 1

    这是一个根本性的错误:

    result = methodInfo.Invoke(methodInfo, parametersArray);
    

    您正在 MethodInfo 的实例上调用该方法 . 您需要传入要调用的对象类型的实例 .

    result = methodInfo.Invoke(classInstance, parametersArray);
    
  • 20

    提供的解决方案不适用于从远程程序集加载的类型的实例 . 为此,这里有一个适用于所有情况的解决方案,它涉及通过CreateInstance调用返回的类型的显式类型重新映射 .

    这就是我需要创建classInstance的方法,因为它位于远程程序集中 .

    // sample of my CreateInstance call with an explicit assembly reference
    object classInstance = Activator.CreateInstance(assemblyName, type.FullName);
    

    但是,即使上面提供的答案,您仍然会得到相同的错误 . 以下是如何进行:

    // first, create a handle instead of the actual object
    ObjectHandle classInstanceHandle = Activator.CreateInstance(assemblyName, type.FullName);
    // unwrap the real slim-shady
    object classInstance = classInstanceHandle.Unwrap(); 
    // re-map the type to that of the object we retrieved
    type = classInstace.GetType();
    

    然后像这里提到的其他用户那样做 .

  • 1

    我会像这样使用它,它的方式更短,它不会给任何问题

    dynamic result = null;
            if (methodInfo != null)
            {
                ParameterInfo[] parameters = methodInfo.GetParameters();
                object classInstance = Activator.CreateInstance(type, null);
                result = methodInfo.Invoke(classInstance, parameters.Length == 0 ? null : parametersArray);
            }
    
  • 207
    Assembly assembly = Assembly.LoadFile(@"....bin\Debug\TestCases.dll");
           //get all types
            var testTypes = from t in assembly.GetTypes()
                            let attributes = t.GetCustomAttributes(typeof(NUnit.Framework.TestFixtureAttribute), true)
                            where attributes != null && attributes.Length > 0
                            orderby t.Name
                            select t;
    
            foreach (var type in testTypes)
            {
                //get test method in types.
                var testMethods = from m in type.GetMethods()
                                  let attributes = m.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute), true)
                                  where attributes != null && attributes.Length > 0
                                  orderby m.Name
                                  select m;
    
                foreach (var method in testMethods)
                {
                    MethodInfo methodInfo = type.GetMethod(method.Name);
    
                    if (methodInfo != null)
                    {
                        object result = null;
                        ParameterInfo[] parameters = methodInfo.GetParameters();
                        object classInstance = Activator.CreateInstance(type, null);
    
                        if (parameters.Length == 0)
                        {
                            // This works fine
                            result = methodInfo.Invoke(classInstance, null);
                        }
                        else
                        {
                            object[] parametersArray = new object[] { "Hello" };
    
                            // The invoke does NOT work;
                            // it throws "Object does not match target type"             
                            result = methodInfo.Invoke(classInstance, parametersArray);
                        }
                    }
    
                }
            }
    
  • 3

    我尝试使用上面提出的所有建议的答案,但似乎没有什么对我有用 . 所以我想在这里解释一下对我有用的东西 .

    我相信如果您正在调用下面的 Main 之类的方法,或者甚至在问题中使用单个参数,您只需将参数类型从 string 更改为 object 即可 . 我有一个类似下面的课程

    //Assembly.dll
    namespace TestAssembly{
        public class Main{
    
            public void Hello()
            { 
                var name = Console.ReadLine();
                Console.WriteLine("Hello() called");
                Console.WriteLine("Hello" + name + " at " + DateTime.Now);
            }
    
            public void Run(string parameters)
            { 
                Console.WriteLine("Run() called");
                Console.Write("You typed:"  + parameters);
            }
    
            public string TestNoParameters()
            {
                Console.WriteLine("TestNoParameters() called");
                return ("TestNoParameters() called");
            }
    
            public void Execute(object[] parameters)
            { 
                Console.WriteLine("Execute() called");
               Console.WriteLine("Number of parameters received: "  + parameters.Length);
    
               for(int i=0;i<parameters.Length;i++){
                   Console.WriteLine(parameters[i]);
               }
            }
    
        }
    }
    

    然后你必须在调用它时将parameterArray传递给一个像下面的对象数组 . 您需要使用以下方法

    private void ExecuteWithReflection(string methodName,object parameterObject = null)
    {
        Assembly assembly = Assembly.LoadFile("Assembly.dll");
        Type typeInstance = assembly.GetType("TestAssembly.Main");
    
        if (typeInstance != null)
        {
            MethodInfo methodInfo = typeInstance.GetMethod(methodName);
            ParameterInfo[] parameterInfo = methodInfo.GetParameters();
            object classInstance = Activator.CreateInstance(typeInstance, null);
    
            if (parameterInfo.Length == 0)
            {
                // there is no parameter we can call with 'null'
                var result = methodInfo.Invoke(classInstance, null);
            }
            else
            {
                var result = methodInfo.Invoke(classInstance,new object[] { parameterObject } );
            }
        }
    }
    

    这种方法可以很容易地调用该方法,可以调用如下方法

    ExecuteWithReflection("Hello");
    ExecuteWithReflection("Run","Vinod");
    ExecuteWithReflection("TestNoParameters");
    ExecuteWithReflection("Execute",new object[]{"Vinod","Srivastav"});
    

相关问题