c# - unity - Reflexión: Cómo invocar el método con parámetros
reflection c# (7)
Cambie "methodInfo" por "classInstance", como en la llamada con la matriz de parámetros null.
result = methodInfo.Invoke(classInstance, parametersArray);
Intento invocar un método a través de la reflexión con parámetros y obtengo:
objeto no coincide con el tipo de objetivo
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 a Test("Run")
, recibo una excepción. ¿Hay algún problema con mi código?
Mi propósito inicial era pasar una serie de objetos, por ejemplo, public void Run(object[] options)
pero esto no funcionó y traté de algo más simple, por ejemplo, una 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);
}
}
}
}
}
La solución proporcionada no funciona para instancias de tipos cargados desde un ensamblaje 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 claseInstance, 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í es cómo hacerlo:
// 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 haz lo que otros usuarios mencionaron aquí.
Lo usaría así, es mucho más corto y no 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);
}
Tienes un error ahí
result = methodInfo.Invoke(methodInfo, parametersArray);
debería ser
result = methodInfo.Invoke(classInstance, parametersArray);
Traté de trabajar con todas las respuestas sugeridas arriba, pero nada parece funcionar para mí. Así que estoy tratando de explicar qué funcionó para mí aquí.
Creo que si está llamando a algún método como el Main
continuación o incluso con un único parámetro como en su pregunta, solo tiene que cambiar el tipo de parámetro de 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 } );
}
Espero que esto ayude
Un error fundamental está 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);
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);
}
}
}
}