web-dev-qa-db-fra.com

Appel dynamique d'une fonction en passant le nom de la fonction sous forme de chaîne

Comment automatiser le processus de création d'une instance et l'exécution dynamique de sa fonction?

Merci

Edit: besoin d'une option pour passer les paramètres aussi. Merci

25
Josh

Voulez-vous simplement appeler un constructeur sans paramètre pour créer l'instance? Le type est-il également spécifié sous forme de chaîne, ou pouvez-vous en faire une méthode générique? Par exemple:

// All error checking omitted. In particular, check the results
// of Type.GetType, and make sure you call it with a fully qualified
// type name, including the Assembly if it's not in mscorlib or
// the current Assembly. The method has to be a public instance
// method with no parameters. (Use BindingFlags with GetMethod
// to change this.)
public void Invoke(string typeName, string methodName)
{
    Type type = Type.GetType(typeName);
    object instance = Activator.CreateInstance(type);
    MethodInfo method = type.GetMethod(methodName);
    method.Invoke(instance, null);
}

ou

public void Invoke<T>(string methodName) where T : new()
{
    T instance = new T();
    MethodInfo method = typeof(T).GetMethod(methodName);
    method.Invoke(instance, null);
}
48
Jon Skeet

Pour invoquer un constructeur, Activator.CreateInstance fera l'affaire. Il a un tas de surcharges pour vous faciliter la vie.

Si votre constructeur est sans paramètre :

object instance = Activator.CreateInstance(type)

Si vous avez besoin de paramètres :

object instance =  Activator.CreateInstance(type, param1, param2)

Pour appeler une méthode, une fois que vous avez l'objet Type , vous pouvez appeler GetMethod pour obtenir la méthode , puis - Invoke (avec ou sans paramètres) pour l'invoquer. Si vous en avez besoin, Invoke vous donnera également la valeur de retour de la fonction que vous appelez (ou null si c'est une méthode void),

Pour un échantillon légèrement plus détaillé (collez dans une application console et c'est parti):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;

namespace Test
{
    public static class Invoker
    {
        public static object CreateAndInvoke(string typeName, object[] constructorArgs, string methodName, object[] methodArgs)
        {
            Type type = Type.GetType(typeName);
            object instance = Activator.CreateInstance(type, constructorArgs);

            MethodInfo method = type.GetMethod(methodName);
            return method.Invoke(instance, methodArgs);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Default constructor, void method
            Invoker.CreateAndInvoke("Test.Tester", null, "TestMethod", null);

            // Constructor that takes a parameter
            Invoker.CreateAndInvoke("Test.Tester", new[] { "constructorParam" }, "TestMethodUsingValueFromConstructorAndArgs", new object[] { "moo", false });

            // Constructor that takes a parameter, invokes a method with a return value
            string result = (string)Invoker.CreateAndInvoke("Test.Tester", new object[] { "constructorValue" }, "GetContstructorValue", null);
            Console.WriteLine("Expect [constructorValue], got:" + result);

            Console.ReadKey(true);
        }
    }

    public class Tester
    {
        public string _testField;

        public Tester()
        {
        }

        public Tester(string arg)
        {
            _testField = arg;
        }

        public void TestMethod()
        {
            Console.WriteLine("Called TestMethod");
        }

        public void TestMethodWithArg(string arg)
        {
            Console.WriteLine("Called TestMethodWithArg: " + arg);
        }

        public void TestMethodUsingValueFromConstructorAndArgs(string arg, bool arg2)
        {
            Console.WriteLine("Called TestMethodUsingValueFromConstructorAndArg " + arg + " " + arg2 + " " + _testField);
        }

        public string GetContstructorValue()
        {
            return _testField;
        }
    }
}
20
Nader Shirazie

En supposant que la méthode que vous souhaitez invoquer ne prend aucun paramètre:

public void InvokeMethod(Type type, string methodName)
{
    object instance = Activator.CreateInstance(type);
    MethodInfo method = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

    method.Invoke(instance, null);
}
7
Fredrik Mörk

Je pense que votre problème est un peu trop générique ici, je fournis ici une solution avec certaines hypothèses.

Hypothèse: vous avez un typeName (chaîne), methodName (chaîne) et un paramètre (de SomeType).

public static void InvokeMethod(string typeName, string methodName, SomeType objSomeType) {
      Type type = Type.GetType(typeName);
      if(type==null) {
        return;
      }
      object instance = Activator.CreateInstance(type); //Type must have a parameter-less contructor, or no contructor.   
      MethodInfo methodInfo =type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public);
      if(methodInfo==null) {
        return;
      }
      methodInfo.Invoke(instance, new[] { objSomeType });  
    } 

faites-moi savoir si mes hypothèses sont fausses.

3
Manish Basantani

Pour passer les paramètres dynamiquement Ici, j'ai pris params string [] args, car différentes fonctions ont un nombre différent de paramètres.

public void Invoke(string typeName,string functionName,params string[] args)
    {

     Type type = Type.GetType(typeName);
     dynamic c=Activator.CreateInstance(type);
     //args contains the parameters(only string type)
     type.InvokeMember(functionName,BindingFlags.InvokeMethod,null,c,args);   

    }
2
chirag pathak