it-swarm.com.de

Reflection: Aufrufen der Methode mit Parametern

Ich versuche eine Methode über Reflection mit Parametern aufzurufen und erhalte:

objekt stimmt nicht mit Zieltyp überein

Wenn ich eine Methode ohne Parameter aufrufe, funktioniert sie einwandfrei. Basierend auf dem folgenden Code, wenn ich die Methode Test("TestNoParameters") aufrufe, funktioniert es einwandfrei. Wenn ich jedoch Test("Run") aufrufe, erhalte ich eine Ausnahme. Stimmt etwas mit meinem Code nicht?

Mein ursprünglicher Zweck bestand darin, eine Reihe von Objekten, z.B. public void Run(object[] options) aber das hat nicht funktioniert und ich habe etwas einfacheres ausprobiert, z. Saite ohne Erfolg.

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

Ändern Sie "methodInfo" in "classInstance", genau wie beim Aufruf mit dem Null-Parameter-Array.

  result = methodInfo.Invoke(classInstance, parametersArray);
219
womp

Sie haben genau dort einen Fehler

result = methodInfo.Invoke(methodInfo, parametersArray);

es sollte sein

result = methodInfo.Invoke(classInstance, parametersArray);
28
Oleg I.

Ein grundlegender Fehler ist hier:

result = methodInfo.Invoke(methodInfo, parametersArray); 

Sie rufen die Methode für eine Instanz von MethodInfo auf. Sie müssen eine Instanz des Objekttyps übergeben, auf den Sie zugreifen möchten.

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

Die bereitgestellte Lösung funktioniert nicht für Instanzen von Typen, die von einer Remote-Assembly geladen wurden. Hier ist eine Lösung, die in allen Situationen funktioniert und eine explizite Neuzuordnung des Typs umfasst, der durch den CreateInstance-Aufruf zurückgegeben wurde.

So muss ich meine classInstance erstellen, da sie sich in einer Remote-Assembly befand.

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

Selbst mit der oben angegebenen Antwort erhalten Sie jedoch den gleichen Fehler. So gehen Sie vor:

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

Dann mach das wie die anderen hier genannten User.

10
Martin Kool

Ich würde es so benutzen, es ist viel kürzer und es wird keine Probleme geben

        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);
        }
4
Nick N.
 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);
                    }
                }

            }
        }
2
M Fatih Koca

Ich habe versucht, mit allen oben vorgeschlagenen Antworten zu arbeiten, aber nichts scheint für mich zu funktionieren. Also versuche ich zu erklären, was hier für mich funktioniert hat.

Ich glaube, wenn Sie eine Methode wie die unten stehende Main aufrufen oder sogar einen einzelnen Parameter wie in Ihrer Frage verwenden, müssen Sie nur den Parametertyp von string in object ändern. ] damit dies funktioniert. Ich habe eine Klasse wie unten

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

    }
}

Dann müssen Sie den ParameterArray in einem Objektarray wie folgt übergeben, während Sie es aufrufen. Die folgende Methode ist das, was Sie benötigen, um zu arbeiten

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

Diese Methode erleichtert das Aufrufen der Methode. Sie kann wie folgt aufgerufen werden

ExecuteWithReflection("Hello");
ExecuteWithReflection("Run","Vinod");
ExecuteWithReflection("TestNoParameters");
ExecuteWithReflection("Execute",new object[]{"Vinod","Srivastav"});
2
Vinod Srivastav

Ich rufe den gewichteten Durchschnitt durch Reflexion auf. Und hatte Methode mit mehr als einem Parameter verwendet.

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
1
Sachin Pete