反射:如何使用参数调用方法
Posted
技术标签:
【中文标题】反射:如何使用参数调用方法【英文标题】:Reflection: How to Invoke Method with parameters 【发布时间】:2011-01-13 05:29:11 【问题描述】:我试图通过带参数的反射调用一个方法,我得到:
对象与目标类型不匹配
如果我调用不带参数的方法,它可以正常工作。基于以下代码,如果我调用方法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);
【问题讨论】:
正确的行是 object[] parametersArray = new object[] new object[] "Hello" ; 如果你知道有一个类型总是先加载,你可以在上面放一个静态ctor。 【参考方案1】:我发布这个答案是因为很多访问者从谷歌进入这里来解决这个问题。
string result = this.GetType().GetMethod("Print").Invoke(this, new object[]"firstParam", 157, "third_Parammmm" );
当外部 .dll - 而不是 this.GetType()
时,您可以使用 typeof(YourClass)
。
【讨论】:
【参考方案2】:在 .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
【讨论】:
【参考方案3】:我正在通过反射调用加权平均值。并且使用了多个参数的方法。
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
【讨论】:
【参考方案4】:我尝试使用上述所有建议的答案,但似乎对我没有任何用处。所以我想在这里解释什么对我有用。
我相信,如果您正在调用下面的 Main
之类的方法,或者甚至在您的问题中使用单个参数,您只需将参数类型从 string
更改为 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]);
然后,您必须在调用它时将 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 );
该方法方便调用方法,可以如下调用
ExecuteWithReflection("Hello");
ExecuteWithReflection("Run","Vinod");
ExecuteWithReflection("TestNoParameters");
ExecuteWithReflection("Execute",new object[]"Vinod","Srivastav");
【讨论】:
【参考方案5】: 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】:我会这样使用它,它的方式更短,不会有任何问题
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);
【讨论】:
【参考方案7】:提供的解决方案不适用于从远程程序集加载的类型实例。为此,这里有一个适用于所有情况的解决方案,它涉及对通过 CreateInstance 调用返回的类型进行显式类型重新映射。
这就是我需要创建类实例的方式,因为它位于远程程序集中。
// 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();
然后按照此处提到的其他用户进行操作。
【讨论】:
【参考方案8】:你那里有一个错误
result = methodInfo.Invoke(methodInfo, parametersArray);
应该是
result = methodInfo.Invoke(classInstance, parametersArray);
【讨论】:
【参考方案9】:这里有一个根本性的错误:
result = methodInfo.Invoke(methodInfo, parametersArray);
您正在MethodInfo
的实例上调用该方法。您需要传入要调用的对象类型的实例。
result = methodInfo.Invoke(classInstance, parametersArray);
【讨论】:
【参考方案10】:将“methodInfo”更改为“classInstance”,就像在使用空参数数组的调用中一样。
result = methodInfo.Invoke(classInstance, parametersArray);
【讨论】:
这有效,除非使用远程程序集的实例。问题是它溢出了同样的错误,这不是很有帮助。我花了几个小时试图修复它,并为我的案例和此处提供的案例发布了一个新的通用解决方案。万一有人需要它:) 如果参数是多种类型的,那么数组应该是怎样的呢?对象数组?? 是的,如果参数中有多种类型,它应该是一个对象[]以上是关于反射:如何使用参数调用方法的主要内容,如果未能解决你的问题,请参考以下文章