J'essaie d'invoquer une méthode via une réflexion avec des paramètres et j'obtiens:
l'objet ne correspond pas au type de cible
Si j'appelle une méthode sans paramètre, cela fonctionne bien. Basé sur le code suivant si j'appelle la méthode Test("TestNoParameters")
, cela fonctionne bien. Cependant, si j'appelle Test("Run")
, j'obtiens une exception. Quelque chose ne va pas avec mon code?
Mon objectif initial était de transmettre un tableau d'objets, par exemple public void Run(object[] options)
mais cela n'a pas fonctionné et j'ai essayé quelque chose de plus simple, par exemple. string sans succès.
// 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);
}
}
}
}
}
Remplacez "methodInfo" par "classInstance", comme dans l'appel avec le tableau de paramètres null.
result = methodInfo.Invoke(classInstance, parametersArray);
Vous avez un bug juste là
result = methodInfo.Invoke(methodInfo, parametersArray);
cA devrait etre
result = methodInfo.Invoke(classInstance, parametersArray);
Une erreur fondamentale est ici:
result = methodInfo.Invoke(methodInfo, parametersArray);
Vous appelez la méthode sur une instance de MethodInfo
. Vous devez transmettre une instance du type d'objet sur lequel vous souhaitez appeler.
result = methodInfo.Invoke(classInstance, parametersArray);
La solution fournie ne fonctionne pas pour les instances de types chargés à partir d'un assembly distant. Pour ce faire, voici une solution qui fonctionne dans toutes les situations et qui implique un remappage explicite de type du type renvoyé via l'appel CreateInstance.
Voici comment créer mon classInstance, car il se trouvait dans un assembly distant.
// sample of my CreateInstance call with an explicit Assembly reference
object classInstance = Activator.CreateInstance(assemblyName, type.FullName);
Cependant, même avec la réponse fournie ci-dessus, vous obtiendrez toujours la même erreur. Voici comment s'y prendre:
// 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();
Ensuite, faites comme les autres utilisateurs mentionnés ici.
Je voudrais l'utiliser comme ça, sa façon de faire est plus courte et cela ne posera aucun problème
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);
}
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);
}
}
}
}
J'ai essayé de travailler avec toutes les réponses suggérées ci-dessus mais rien ne semble fonctionner pour moi. J'essaie donc d'expliquer ce qui a fonctionné pour moi ici.
Je crois que si vous appelez une méthode comme la Main
ci-dessous ou même avec un paramètre unique, comme dans votre question, il vous suffit de changer le type de paramètre de string
à object
pour cela. travailler. J'ai une classe comme ci-dessous
//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]);
}
}
}
}
Ensuite, vous devez passer le parameterArray dans un tableau d'objets comme ci-dessous tout en l'invoquant. La méthode suivante est ce que vous devez travailler
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 } );
}
}
}
Cette méthode facilite l’invocation de la méthode, elle peut être appelée comme suit
ExecuteWithReflection("Hello");
ExecuteWithReflection("Run","Vinod");
ExecuteWithReflection("TestNoParameters");
ExecuteWithReflection("Execute",new object[]{"Vinod","Srivastav"});
J'appelle la moyenne pondérée par réflexion. Et avait utilisé la méthode avec plus d'un paramètre.
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