32 votes

Construit un délégué à partir de MethodInfo?

Après googler et à l'atterrissage sur DONC et après avoir lu cette autre question

Est-il possible de construire un bon Délégué à partir d'un MethodInfo si vous ne connaissez pas le nombre ou les types de paramètres au moment de la compilation?

En savoir plus sur cette: peut-on le faire avec élégance, sans l'utilisation de la Réflexion.Émettre ou le type des constructeurs?

C'est sorta une déception pour moi, car Délégué.CreateDelegate me demande de choisir le bon type de Délégué en tant que premier paramètre ou d'autre, il serait de lancer des exceptions ou invoquer une méthode incorrecte.

Je suis en train de construire certains ninja engrenages et cela aide beaucoup... Merci!


Voici une solution générique:

/// <summary>
/// Builds a Delegate instance from the supplied MethodInfo object and a target to invoke against.
/// </summary>
public static Delegate ToDelegate(MethodInfo mi, object target)
{
    if (mi == null) throw new ArgumentNullException("mi");

    Type delegateType;

    var typeArgs = mi.GetParameters()
        .Select(p => p.ParameterType)
        .ToList();

    // builds a delegate type
    if (mi.ReturnType == typeof(void)) {
        delegateType = Expression.GetActionType(typeArgs.ToArray());

    } else {
        typeArgs.Add(mi.ReturnType);
        delegateType = Expression.GetFuncType(typeArgs.ToArray());
    }

    // creates a binded delegate if target is supplied
    var result = (target == null)
        ? Delegate.CreateDelegate(delegateType, mi)
        : Delegate.CreateDelegate(delegateType, target, mi);

    return result;
}


Note: je fais construire une application Silverlight qui permettrait de remplacer un haut-ans-il y a javascript de l'application dans laquelle j'ai plusieurs Javascript, des interfaces d'appels dans le même Silverlight [ScriptableMember de la méthode].

Tous ceux héritage JS interfaces doivent être pris en charge ainsi que la nouvelle interface pour l'accès à de nouvelles fonctionnalités, donc quelque chose qui automatiquement des configurations de la JS interface et les "délégués" l'appel pour le droit de Silverlight méthode permet d'accélérer le travail beaucoup.

Je ne peux pas poster le code ici, de sorte que le résumé.

22voto

Marc Gravell Points 482669

Pour être honnête, si vous ne connaissez pas le type au moment de la compilation, il n'y a pas une énorme quantité de profit dans la création d'un Delegate. Vous ne voulez pas utiliser DynamicInvoke; il sera aussi lent que la réflexion. La principale exception à cette règle est lorsqu'il y a un délégué de type tapi dans l'ombre, par exemple lors de l'inscription à un événement auquel cas EventInfo fait de cette disposition.

Pour info, dans .NET 3.5 sur Expression, il y a:

Expression.GetActionType(params Type[] typeArgs);
Expression.GetFuncType(params Type[] typeArgs)

Qui pourraient aider à une mesure:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
static class Program {
    static void Main() {
        DoStuff("Test1");
        DoStuff("Test2");
    }
    static void DoStuff(string methodName) {
        MethodInfo method = typeof(Program).GetMethod(methodName);
        List<Type> args = new List<Type>(
            method.GetParameters().Select(p => p.ParameterType));
        Type delegateType;
        if (method.ReturnType == typeof(void)) {
            delegateType = Expression.GetActionType(args.ToArray());
        } else {
            args.Add(method.ReturnType);
            delegateType = Expression.GetFuncType(args.ToArray());
        }
        Delegate d = Delegate.CreateDelegate(delegateType, null, method);
        Console.WriteLine(d);
    }
    public static void Test1(int i, DateTime when) { }
    public static float Test2(string x) { return 0; }
}

7voto

Jon Skeet Points 692016

Si vous ne connaissez pas le nombre ou le type de paramètres à l'avance, sans doute cela signifie que vous ne connaissez pas le type de délégué que vous voulez créer?

Si c'est le cas, vous êtes coincé dans l'absolument le cas général.

Cependant, pour la plupart des communes de cas (pas de ref/paramètres de sortie, peu de suffisamment de paramètres pour utiliser l'un des types existants), vous pourriez sortir avec un de la Func ou Action des délégués. (.NET 4.0 a Func/Action types pour un grand nombre de paramètres, si vraiment vous ne devez pas vous inquiéter au sujet de la/paramètres de ref.) Si la méthode n'est pas de type de retour void utiliser Func, sinon utilisez Action. Quelle type à utiliser en fonction du nombre de paramètres, par exemple

static readonly Type[] FuncTypes = { typeof(Func), 
    typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), /* etc */ };

Utiliser Type.MakeGenericType en utilisant les types de paramètres et le type de retour pour obtenir le bon type de délégué, puis Delegate.CreateDelegate devrait fonctionner.

Je n'ai pas le temps de travailler un échantillon de droit maintenant, mais laissez-moi savoir si vous voulez me faire plus tard.

Une question: comment avez-vous l'intention d'utiliser ce délégué? Quelque chose d'autre va avoir besoin de savoir comment l'exécuter, sûrement...

7voto

0xbadf00d Points 2554

Pourquoi ça compliqué?

 public static Delegate CreateDelegate(this MethodInfo method)
{
    return Delegate.CreateDelegate
    (
        Expression.GetDelegateType
        (
            method.GetParameters()
                .Select(p => p.ParameterType)
                .Concat(new Type[] { method.ReturnType })
                .ToArray()
        ),
        null,
        method
    );   
}
 

[Note: j'ai préfixé cette méthode "Créer ...". "To ..." est source de confusion car il vous induit en erreur que c'est une conversion.]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X