2010-02-04 15 views
152

Estoy tratando de invocar un método a través de la reflexión con los parámetros y me sale:Reflexión: ¿Cómo invocar el método con parámetros

objeto no coincide con destino tipo

Si invoco un método sin parámetros, funciona bien. Basado en el siguiente código si llamo al método Test("TestNoParameters"), funciona bien. Sin embargo, si llamo al Test("Run"), recibo una excepción. ¿Hay algún problema con mi código?

Mi propósito inicial era pasar una serie de objetos, p. public void Run(object[] options) pero esto no funcionó y traté de algo más simple, p. cadena sin éxito

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

Respuesta

182

Cambia "methodInfo" a "classInstance", como en la llamada con la matriz de parámetros null.

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

eso es lo que estamos aquí;) – womp

+0

Esto funciona, excepto cuando se trabaja con una instancia de un montaje remoto. El problema es que derrama el mismo error que no es muy útil. Pasé varias horas intentando solucionarlo y publiqué una nueva solución general tanto para mi caso como para el proporcionado aquí. En caso de que alguien lo necesite :) –

+1

si los parámetros son de varios tipos, ¿cómo debería ser la matriz? una serie de objetos? –

18

Un error fundamental es aquí:

result = methodInfo.Invoke(methodInfo, parametersArray); 

está invocando el método en una instancia de MethodInfo. Debe pasar una instancia del tipo de objeto sobre el que desea invocar.

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

ha encontrado un error ahí

result = methodInfo.Invoke(methodInfo, parametersArray); 

debe ser

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

La solución proporcionada no funciona para instancias de tipos cargados desde un montaje remoto. Para hacerlo, aquí hay una solución que funciona en todas las situaciones, lo que implica una nueva asignación explícita de tipo del tipo devuelto a través de la llamada CreateInstance.

Así es como tengo que crear mi classInstance, ya que se encuentra en un conjunto remoto.

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

Sin embargo, incluso con la respuesta proporcionada anteriormente, igual obtendría el mismo error. Aquí está cómo proceder:

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

Luego haga como los otros usuarios mencionados aquí.

3

lo usaría como este, su camino más corto y no va a dar ningún 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); 
     } 
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

Traté de trabajar con todas las respuestas sugeridas anteriormente, pero nada parece funcionar para mí. Así que estoy tratando de explicar qué funcionó para mí aquí.

Creo que si está llamando a un método como el Main abajo o incluso con un único parámetro como en su pregunta, sólo hay que cambiar el tipo de parámetro desde string a object para que esto funcione

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

Luego debe pasar el parámetro Array dentro de una matriz de objetos como la siguiente al invocarlo.

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

Esperanza esto ayuda

Cuestiones relacionadas