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

时间:2010-02-04 19:02:49

标签: c# reflection parameters methods invoke

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

  

对象与目标类型不匹配

如果我调用没有参数的方法,它可以正常工作。如果我调用方法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);
                }
            }
        }
    }
}

10 个答案:

答案 0 :(得分:215)

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

  result = methodInfo.Invoke(classInstance, parametersArray);

答案 1 :(得分:27)

你有错误

result = methodInfo.Invoke(methodInfo, parametersArray);

应该是

result = methodInfo.Invoke(classInstance, parametersArray);

答案 2 :(得分:21)

这是一个根本性的错误:

result = methodInfo.Invoke(methodInfo, parametersArray); 

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

result = methodInfo.Invoke(classInstance, parametersArray);

答案 3 :(得分:10)

提供的解决方案不适用于从远程程序集加载的类型的实例。为此,这里有一个适用于所有情况的解决方案,它涉及通过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(); 

然后按照此处提到的其他用户进行操作。

答案 4 :(得分:4)

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

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

答案 5 :(得分:2)

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

            }
        }

答案 6 :(得分:2)

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

我相信如果您正在调用某个方法,例如下面的Main,或者甚至使用您问题中的单个参数,则只需将参数类型从string更改为{{1}为了这个工作。我有一个类似下面的课程

object

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

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

    }
}

此方法可以轻松调用该方法,可以按以下方式调用

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

答案 7 :(得分:1)

我正在通过反射调用加权平均值。并且使用了带有多个参数的方法。

Class cls = Class.forName(propFile.getProperty(formulaTyp));// reading class name from file

Object weightedobj = cls.newInstance(); // invoke empty constructor

Class<?>[] paramTypes = { String.class, BigDecimal[].class, BigDecimal[].class }; // 3 parameter having first is method name and other two are values and their weight
Method printDogMethod = weightedobj.getClass().getMethod("applyFormula", paramTypes); // created the object 
return BigDecimal.valueOf((Double) printDogMethod.invoke(weightedobj, formulaTyp, decimalnumber, weight)); calling the method

答案 8 :(得分:0)

我之所以发布此答案,是因为许多访客从Google此处输入此问题。


"Values":{
.
.
"EventHub:Name": "your event hub name",
"EventHub:ConsumerGroup": "your event hub consumer group",
"EventHub:ConnectionString": "your event hub connection string"
}

当使用外部.dll而不是string result = this.GetType().GetMethod("Print").Invoke(this, new object[]{"firstParam", 157, "third_Parammmm" } ); 时,您可以使用this.GetType()

答案 9 :(得分:0)

在.Net 4.7.2上调用从外部程序集加载的类中的方法,您可以在VB.net中使用以下代码

isBefore()