Riflessione: come richiamare il metodo con i parametri

Sto cercando di invocare un metodo tramite riflessione con parametri e ottengo:

l’object non corrisponde al tipo di destinazione

Se invoco un metodo senza parametri, funziona correttamente. Basato sul seguente codice se chiamo il metodo Test("TestNoParameters") , funziona Test("TestNoParameters") . Tuttavia, se chiamo Test("Run") , ottengo un’eccezione. C’è qualcosa che non va nel mio codice?

Il mio scopo iniziale era passare una serie di oggetti, ad esempio public void Run(object[] options) ma questo non ha funzionato e ho provato qualcosa di più semplice, ad es. Stringa senza successo.

 // 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); } } } } } 

Cambia “methodInfo” in “classInstance”, proprio come nella chiamata con l’array di parametri null.

  result = methodInfo.Invoke(classInstance, parametersArray); 

Hai un bug proprio lì

 result = methodInfo.Invoke(methodInfo, parametersArray); 

dovrebbe essere

 result = methodInfo.Invoke(classInstance, parametersArray); 

Un errore fondamentale è qui:

 result = methodInfo.Invoke(methodInfo, parametersArray); 

Stai invocando il metodo su un’istanza di MethodInfo . È necessario passare un’istanza del tipo di object su cui si desidera richiamare.

 result = methodInfo.Invoke(classInstance, parametersArray); 

La soluzione fornita non funziona per le istanze di tipi caricati da un assembly remoto. Per fare ciò, ecco una soluzione che funziona in tutte le situazioni, il che implica un re-mapping esplicito del tipo restituito tramite la chiamata CreateInstance.

Ecco come ho bisogno di creare la mia classInstance, poiché si trovava in un assembly remoto.

 // sample of my CreateInstance call with an explicit assembly reference object classInstance = Activator.CreateInstance(assemblyName, type.FullName); 

Tuttavia, anche con la risposta fornita sopra, avresti comunque lo stesso errore. Ecco come procedere:

 // 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(); 

Quindi fai come gli altri utenti menzionati qui.

Lo userei in questo modo, è più breve e non darà alcun problema

  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); } 

Ho provato a lavorare con tutte le risposte suggerite sopra ma nulla sembra funzionare per me. Quindi sto cercando di spiegare cosa ha funzionato per me qui.

Credo che se stai chiamando un metodo come Main o anche con un singolo parametro come nella tua domanda, devi solo cambiare il tipo di parametro da string ad object affinché questo funzioni

 class Class1 { public static void Execute(object[] str) {...} } 

Quindi devi passare il parametroArray all’interno di un array di oggetti come di seguito mentre lo invochi.

 Assembly assembly = Assembly.LoadFile("...Assembly1.dll"); Type type = assembly.GetType("TestAssembly.Main"); if (type != null) { MethodInfo mi = typeInstance.GetType().GetMethod("Execute"); ParameterInfo[] parameters = mi.GetParameters(); object classInstance = Activator.CreateInstance(typeInstance.GetType(), null); if (parameters.Length == 0) { // This works fine var result = mi.Invoke(classInstance, null); } else { object[] parametersArray = new object[] { "Hello","bye" }; var result = mi.Invoke(classInstance,new object[] { parametersArray } ); } } 

Spero che questo ti aiuti

  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); } } } }