C# 反思:如何使用参数调用方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2202381/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reflection: How to Invoke Method with parameters
提问by Ioannis
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?
如果我调用一个没有参数的方法,它工作正常。如果我调用该方法Test("TestNoParameters")
,则基于以下代码,它工作正常。但是,如果我调用Test("Run")
,则会出现异常。我的代码有问题吗?
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.
我最初的目的是传递一个对象数组,例如,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);
}
}
}
}
}
采纳答案by womp
Change "methodInfo" to "classInstance", just like in the call with the null parameter array.
将“methodInfo”更改为“classInstance”,就像在使用空参数数组的调用中一样。
result = methodInfo.Invoke(classInstance, parametersArray);
回答by jason
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.
您正在 的实例上调用该方法MethodInfo
。您需要传入要调用的对象类型的实例。
result = methodInfo.Invoke(classInstance, parametersArray);
回答by Oleg I.
You have a bug right there
你有一个错误
result = methodInfo.Invoke(methodInfo, parametersArray);
it should be
它应该是
result = methodInfo.Invoke(classInstance, parametersArray);
回答by Martin Kool
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.
然后按照此处提到的其他用户进行操作。
回答by Nick N.
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);
}
回答by M Fatih Koca
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);
}
}
}
}
回答by Vinod Srivastav
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. I have a class like below
我相信,如果您正在调用Main
如下所示的某些方法,甚至在您的问题中使用单个参数,您只需将参数类型从string
to更改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]);
}
}
}
}
Then you have to pass the parameterArray inside an object array like below while invoking it. The following method is what you need to work
然后,您必须在调用它时将 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 } );
}
}
}
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"});
回答by Sachin Pete
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