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

对象与目标类型不匹配

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

当前回答

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

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

其他回答

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

            }
        }

我通过反射调用加权平均。并采用了具有多个参数的方法。

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

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

        Dim assembly As Reflection.Assembly = Nothing
        Try
            assembly = Reflection.Assembly.LoadFile(basePath & AssemblyFileName)
            Dim typeIni = assembly.[GetType](AssemblyNameSpace & "." & "nameOfClass")
            Dim iniClass = Activator.CreateInstance(typeIni, True)
            Dim methodInfo = typeIni.GetMethod("nameOfMethod")

            'replace nothing by a parameter array if you need to pass var. paramenters
            Dim parametersArray As Object() = New Object() {...}
            'without parameters is like this
            Dim result = methodInfo.Invoke(iniClass, Nothing)
        Catch ex As Exception
            MsgBox("Error initializing main layout:" & ex.Message)
            Application.Exit()
            Exit Sub
        End Try

这里有个虫子

result = methodInfo.Invoke(methodInfo, parametersArray);

应该是这样

result = methodInfo.Invoke(classInstance, parametersArray);

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

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