Créer un Func ou une Action pour n'importe quelle méthode

c# expression-trees lambda reflection

Question

Mon application fonctionne avec le chargement dynamique des dll, en fonction des paramètres de la base de données (noms de fichier, de classe et de méthode). Pour faciliter, accélérer et réduire l'utilisation de la réflexion, j'aimerais disposer d'une mémoire cache ....

Suivant l’idée que l’utilisation:

 MethodInfo.Invoke

N'y a rien de performatif ( Performance de la réflexion - Créer un délégué (propriétés C #) ). J'aimerais traduire tout appel aux méthodes. J'ai pensé à quelque chose qui fonctionnerait comme ceci:

 MethodInfo.Invoke

Une exigence est que tous les paramètres puissent être des objets.

J'essaie de traiter les expressions, et jusqu'à présent, j'ai quelque chose comme ceci:

 MethodInfo.Invoke

 MethodInfo.Invoke

Est-il possible de simplifier ce code? (Je crois qu'il est possible de créer une méthode en utilisant seulement générique ..) Et quand vous avez 3, 4, 5, des paramètres comme moi?


Je pensais, et s'il y avait quelque chose comme ça:

https://codereview.stackexchange.com/questions/1070/generic-advanced-delegate-createdelegate-using-expression-trees

mais j'aurai plus d'un paramètre (en action ou fonction), ce paramètre (premier paramètre) un objet à exécuter. Est-ce possible?

Réponse acceptée

J'ai créé un exemple de programme qui répond à toutes vos exigences (je pense!)

class Program
{
    class MyType
    {
        public MyType(int i) { this.Value = i; }

        public void SetValue(int i) { this.Value = i; }

        public void SetSumValue(int a, int b) { this.Value = a + b; }

        public int Value { get; set; }
    }

    public static void Main()
    {
        Type type = typeof(MyType);

        var mi = type.GetMethod("SetValue");

        var obj1 = new MyType(1);
        var obj2 = new MyType(2);

        var action = DelegateBuilder.BuildDelegate<Action<object, int>>(mi);

        action(obj1, 3);
        action(obj2, 4);

        Console.WriteLine(obj1.Value);
        Console.WriteLine(obj2.Value);

        // Sample passing a default value for the 2nd param of SetSumValue.
        var mi2 = type.GetMethod("SetSumValue");

        var action2 = DelegateBuilder.BuildDelegate<Action<object, int>>(mi2, 10);

        action2(obj1, 3);
        action2(obj2, 4);

        Console.WriteLine(obj1.Value);
        Console.WriteLine(obj2.Value);

        // Sample without passing a default value for the 2nd param of SetSumValue.
        // It will just use the default int value that is 0.
        var action3 = DelegateBuilder.BuildDelegate<Action<object, int>>(mi2);

        action3(obj1, 3);
        action3(obj2, 4);

        Console.WriteLine(obj1.Value);
        Console.WriteLine(obj2.Value);
    }
}

Classe DelegateBuilder:

class Program
{
    class MyType
    {
        public MyType(int i) { this.Value = i; }

        public void SetValue(int i) { this.Value = i; }

        public void SetSumValue(int a, int b) { this.Value = a + b; }

        public int Value { get; set; }
    }

    public static void Main()
    {
        Type type = typeof(MyType);

        var mi = type.GetMethod("SetValue");

        var obj1 = new MyType(1);
        var obj2 = new MyType(2);

        var action = DelegateBuilder.BuildDelegate<Action<object, int>>(mi);

        action(obj1, 3);
        action(obj2, 4);

        Console.WriteLine(obj1.Value);
        Console.WriteLine(obj2.Value);

        // Sample passing a default value for the 2nd param of SetSumValue.
        var mi2 = type.GetMethod("SetSumValue");

        var action2 = DelegateBuilder.BuildDelegate<Action<object, int>>(mi2, 10);

        action2(obj1, 3);
        action2(obj2, 4);

        Console.WriteLine(obj1.Value);
        Console.WriteLine(obj2.Value);

        // Sample without passing a default value for the 2nd param of SetSumValue.
        // It will just use the default int value that is 0.
        var action3 = DelegateBuilder.BuildDelegate<Action<object, int>>(mi2);

        action3(obj1, 3);
        action3(obj2, 4);

        Console.WriteLine(obj1.Value);
        Console.WriteLine(obj2.Value);
    }
}

Comment ça marche

Le noyau est la méthode BuildDelegate :

static T BuildDelegate<T>(MethodInfo method)

  • T est le type de délégué que vous souhaitez créer.
  • method correspond à MethodInfo de la méthode à appeler par le délégué généré.

Exemple d'appel: var action = BuildDelegate<Action<object, int>>(mi);

Règles pour les paramètres:

  • Si la méthode transmise est une méthode d'instance, le premier paramètre du délégué généré acceptera l'instance de l'objet, qui contient la méthode elle-même. Tous les autres paramètres seront transmis à la méthode.

  • Si la méthode transmise est une méthode statique, tous les paramètres du délégué généré seront transmis à la méthode.

  • Les paramètres manquants auront des valeurs par défaut passées.

  • Les paramètres supplémentaires seront ignorés.

Réponse populaire

Delegate.CreateDelegate est beaucoup plus simple que la construction d'arbres d'expression.

    var assembly = Assembly.GetAssembly(typeof(Foo));

    Type customType = assembly.GetType("Foo");

    var actionMethodInfo = customType.GetMethod("AnyMethod");

    var foo = Activator.CreateInstance(customType);

    Action action = (Action)Delegate.CreateDelegate(typeof(Action), foo, actionMethodInfo);



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi