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

对象与目标类型不匹配

如果我调用一个没有参数的方法,它可以正常工作。根据下面的代码,如果我调用方法Test(“TestNoParameters”),它可以正常工作。然而,如果我调用测试(“运行”),我得到一个异常。我的代码有问题吗?

我最初的目的是传递一个对象数组,例如公共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);
                }
            }
        }
    }
}

当前回答

我会像这样使用它,它更短,不会出任何问题

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

其他回答

我尝试了上面建议的所有答案,但似乎都不适合我。所以我试着解释一下什么对我有用。

我相信,如果你正在调用一些方法,比如下面的Main,甚至像你的问题中那样只有一个参数,你只需要将参数的类型从字符串更改为对象就可以了。我有一个像下面这样的班

//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 static string StaticString()
        { 
                return "static string example";
        }     
        
        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 object ExecuteWithReflection(string methodName,object parameterObject = null)
{
    Assembly assembly = Assembly.LoadFile("Assembly.dll");
    Type typeInstance = assembly.GetType("TestAssembly.Main");
    MethodInfo methodInfo = typeInstance.GetMethod(methodName);
    ParameterInfo[] parameterInfo = methodInfo.GetParameters();

    object result = null;
    
    if (typeInstance != null) //non static
    {       
        if(methodInfo.IsStatic == false)
        {
            //instance is needed to invoke the method
            object classInstance = Activator.CreateInstance(typeInstance, null);

            if (parameterInfo.Length == 0)
            {
                // there is no parameter we can call with 'null'
                result = methodInfo.Invoke(classInstance, null);
            }
            else
            {
                result = methodInfo.Invoke(classInstance,new object[] { parameterObject } );
            }
        }
        else //handle static
        {
            if (parameterInfo.Length == 0)
            {
                // there is no parameter we can call with 'null'
                result = methodInfo.Invoke(null, null); 
            }
            else
            {
                result = methodInfo.Invoke(null,new object[] { parameterObject } );
            }
        }
    }
    
    return result;
}

这个方法使调用方法变得很容易,它可以像下面这样调用

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

将“methodInfo”更改为“classInstance”,就像对空参数数组的调用一样。

  result = methodInfo.Invoke(classInstance, parametersArray);

这是一个根本性的错误:

result = methodInfo.Invoke(methodInfo, parametersArray); 

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

result = methodInfo.Invoke(classInstance, parametersArray);
 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);
                    }
                }

            }
        }

我发布这个答案是因为许多访问者从谷歌进入这里解决这个问题。


string result = this.GetType().GetMethod("Print").Invoke(this, new object[]{"firstParam", 157, "third_Parammmm" } );

当外部.dll -而不是this.GetType(),你可以使用typeof(YourClass)。