Reputation: 3035
I am trying to invoke a method via reflection with parameters and I get:
object does not match target type
If I invoke a method without parameters, it works fine. Based on the following code if I call the method Test("TestNoParameters")
, it works fine. However if I call Test("Run")
, I get an exception. Is something wrong with my code?
My initial purpose was to pass an array of objects e.g. public void Run(object[] options)
but this did not work and I tried something simpler e.g. string without success.
// 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);
}
}
}
}
}
Upvotes: 247
Views: 506497
Reputation: 4255
I tried to work with all the suggested answers above but nothing seems to work for me. So I am trying to explain what worked for me here.
I believe if you are calling some method like in the class Main
below or even with a single parameter as in your question, you just have to change the type of parameter from string
to object
for this to work.
I have created an example class
like below
Assembly.dll
//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]);
}
}
}
}
Then you have to pass the parameterArray
inside an object
array like below while invoking it.
The following method is what you need to call with MethodName
& parameterList
to invoke the method from Assembly.dll
above.
ExecuteMethod
private object ExecuteMethod(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;
}
This method makes it easy to invoke the method, it can be called as following
ExecuteMethod("Hello");
ExecuteMethod("Run","Vinod");
ExecuteMethod("TestNoParameters");
ExecuteMethod("Execute",new object[]{"Vinod","Srivastav"});
ExecuteMethod("StaticString");
Upvotes: 9
Reputation: 56341
I'am posting this answer because many visitors enter here from google for this problem.
string result = this.GetType().GetMethod("Print").Invoke(this, new object[]{"firstParam", 157, "third_Parammmm" } );
when external .dll -instead of this.GetType()
, you might use typeof(YourClass)
.
Upvotes: 8
Reputation: 1911
On .Net 4.7.2 to invoke a method inside a class loaded from an external assembly you can use the following code in 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
Upvotes: 0
Reputation: 21
I m invoking the weighted average through reflection. And had used method with more than one parameter.
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
Upvotes: 1
Reputation: 601
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);
}
}
}
}
Upvotes: 4
Reputation: 13559
I would use it like this, its way shorter and it won't give any problems
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);
}
Upvotes: 6
Reputation: 4245
The provided solution does not work for instances of types loaded from a remote assembly. To do that, here is a solution that works in all situations, which involves an explicit type re-mapping of the type returned through the CreateInstance call.
This is how I need to create my classInstance, as it was located in a remote assembly.
// sample of my CreateInstance call with an explicit assembly reference
object classInstance = Activator.CreateInstance(assemblyName, type.FullName);
However, even with the answer provided above, you'd still get the same error. Here is how to go about:
// 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();
Then do as the other users mentioned here.
Upvotes: 12
Reputation: 821
You have a bug right there
result = methodInfo.Invoke(methodInfo, parametersArray);
it should be
result = methodInfo.Invoke(classInstance, parametersArray);
Upvotes: 34
Reputation: 241583
A fundamental mistake is here:
result = methodInfo.Invoke(methodInfo, parametersArray);
You are invoking the method on an instance of MethodInfo
. You need to pass in an instance of the type of object that you want to invoke on.
result = methodInfo.Invoke(classInstance, parametersArray);
Upvotes: 27
Reputation: 116977
Change "methodInfo" to "classInstance", just like in the call with the null parameter array.
result = methodInfo.Invoke(classInstance, parametersArray);
Upvotes: 273