[英]Reflection: How to Invoke Method with parameters
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.根据以下代码,如果我调用方法
Test("TestNoParameters")
,它工作正常。 However if I call Test("Run")
, I get an exception.但是,如果我调用
Test("Run")
,则会出现异常。 Is something wrong with my code?我的代码有问题吗?
My initial purpose was to pass an array of objects eg public void Run(object[] options)
but this did not work and I tried something simpler eg string without success.我最初的目的是传递一个对象数组,例如
public void Run(object[] options)
但这不起作用,我尝试了一些更简单的东西,例如 string 没有成功。
// 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);
}
}
}
}
}
将“methodInfo”更改为“classInstance”,就像在使用空参数数组的调用中一样。
result = methodInfo.Invoke(classInstance, parametersArray);
You have a bug right there你有一个错误
result = methodInfo.Invoke(methodInfo, parametersArray);
it should be它应该是
result = methodInfo.Invoke(classInstance, parametersArray);
A fundamental mistake is here:一个根本性的错误在这里:
result = methodInfo.Invoke(methodInfo, parametersArray);
You are invoking the method on an instance of MethodInfo
.您正在调用
MethodInfo
实例上的方法。 You need to pass in an instance of the type of object that you want to invoke on.您需要传入要调用的对象类型的实例。
result = methodInfo.Invoke(classInstance, parametersArray);
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.
为此,这里有一个适用于所有情况的解决方案,它涉及通过 CreateInstance 调用返回的类型的显式类型重新映射。
This is how I need to create my classInstance, as it was located in a remote assembly.这是我需要如何创建我的 classInstance,因为它位于远程程序集中。
// 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.然后按照此处提到的其他用户进行操作。
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);
}
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 the 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.我相信,如果您正在调用像下面的
Main
这样的方法,或者甚至在您的问题中使用单个参数,您只需将参数类型从string
更改为object
即可。 I have a class like below我有一个像下面这样的课程
//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]);
}
}
}
}
Then you have to pass the parameterArray inside an object array like below while invoking it.然后,您必须在调用它时将 parameterArray 传递到如下所示的对象数组中。 The following method is what you need to work
以下方法是您需要工作的
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 } );
}
}
}
This method makes it easy to invoke the method, it can be called as following这个方法可以很容易地调用方法,它可以被调用如下
ExecuteWithReflection("Hello");
ExecuteWithReflection("Run","Vinod");
ExecuteWithReflection("TestNoParameters");
ExecuteWithReflection("Execute",new object[]{"Vinod","Srivastav"});
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);
}
}
}
}
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)
.当外部 .dll -而
this.GetType()
,您可以使用typeof(YourClass)
。
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
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在 .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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.