2010-02-04 9 views
152

Je suis en train d'appeler une méthode par réflexion avec des paramètres et je reçois:Réflexion: Comment Invoke Méthode avec des paramètres

objet

ne correspond pas au type cible

Si j'invoque une méthode sans paramètres, ça fonctionne bien. Basé sur le code suivant si j'appelle la méthode Test("TestNoParameters"), cela fonctionne très bien. Cependant si j'appelle Test("Run"), j'obtiens une exception. Quelque chose ne va pas avec mon code?

Mon but initial était de faire passer un tableau d'objets, par ex. public void Run(object[] options) mais cela n'a pas fonctionné et j'ai essayé quelque chose de plus simple, par ex. chaîne 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); 
       } 
      } 
     } 
    } 
} 

Répondre

182

Remplacez "methodInfo" par "classInstance", comme dans l'appel avec le tableau de paramètres null.

result = methodInfo.Invoke(classInstance, parametersArray); 
+24

C'est ce que nous sommes là pour;) – womp

+0

Cela fonctionne, sauf lorsque vous travaillez avec une instance d'un assemblage à distance. Le problème était que cela renvoyait à la même erreur qui n'est pas très utile. J'ai passé plusieurs heures à essayer de le réparer, et posté une nouvelle solution générale à la fois pour mon cas et celui fourni ici. Au cas où quelqu'un en aurait besoin :) –

+1

Si les paramètres sont de types multiples, à quoi devrait ressembler le tableau? un tableau d'objets ?? –

18

Une erreur fondamentale est ici:

result = methodInfo.Invoke(methodInfo, parametersArray); 

Vous invoquez la méthode sur une instance de MethodInfo. Vous devez transmettre une instance du type d'objet que vous souhaitez appeler.

result = methodInfo.Invoke(classInstance, parametersArray); 
23

Vous avez un bug il droit

result = methodInfo.Invoke(methodInfo, parametersArray); 

il devrait être

result = methodInfo.Invoke(classInstance, parametersArray); 
8

La solution proposée ne fonctionne pas pour les instances de types chargés à partir d'un ensemble à distance. Pour ce faire, voici une solution qui fonctionne dans toutes les situations, ce qui implique un re-mappage de type explicite du type renvoyé via l'appel CreateInstance.

Voici comment je dois créer classInstance, car elle se trouvait dans un assemblage distant. Cependant, même avec la réponse fournie ci-dessus, vous obtiendrez toujours la même erreur. Voici comment faire:

// 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.

3

Je l'utiliser comme ceci, son chemin plus court et il ne donnera 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); 
     } 
0
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); 
        } 
       } 

      } 
     } 
0

J'ai essayé de travailler avec toutes les réponses proposées ci-dessus, mais rien ne semble fonctionner pour moi. Donc j'essaie d'expliquer ce qui a fonctionné pour moi ici.

Je crois que si vous appelez une méthode comme le Main ci-dessous ou même avec un seul paramètre que dans votre question, il vous suffit de changer le type de paramètre string-object pour que cela fonctionne

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

Ensuite, vous devez passer le parameterArray à l'intérieur d'un tableau d'objets comme ci-dessous tout en l'invoquant.

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

Hope this helps