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

Ioa*_*nis 187 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);
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

wom*_*omp 223

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

  result = methodInfo.Invoke(classInstance, parametersArray);
Run Code Online (Sandbox Code Playgroud)

  • 如果参数是多种类型,那么数组应该是什么样的?一个对象数组?? (4认同)

小智 28

你有一个错误

result = methodInfo.Invoke(methodInfo, parametersArray);
Run Code Online (Sandbox Code Playgroud)

它应该是

result = methodInfo.Invoke(classInstance, parametersArray);
Run Code Online (Sandbox Code Playgroud)


jas*_*son 23

一个根本的错误在这里:

result = methodInfo.Invoke(methodInfo, parametersArray); 
Run Code Online (Sandbox Code Playgroud)

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

result = methodInfo.Invoke(classInstance, parametersArray);
Run Code Online (Sandbox Code Playgroud)


Mar*_*ool 10

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

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

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

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

// 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(); 
Run Code Online (Sandbox Code Playgroud)

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


T.T*_*dua 8

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


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

当使用外部 .dll 代替 时this.GetType(),您可以使用typeof(YourClass).


Nic*_* N. 5

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

        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);
        }
Run Code Online (Sandbox Code Playgroud)


Vin*_*tav 5

我尝试使用上述所有建议的答案,但似乎对我没有任何作用。所以我试图解释什么对我有用。

我相信,如果您正在调用Main如下所示的某些方法,甚至在您的问题中使用单个参数,您只需将参数类型从stringto更改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]);
           }
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您必须在调用它时将 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 } );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这个方法可以很容易地调用方法,它可以被调用如下

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

  • @DonnyV。对于静态,您可以使用 `methodInfo.Invoke(null, null); 调用 `。请查看更新后的代码 (2认同)