web-dev-qa-db-fra.com

Comment appeler une méthode générique avec un objet Type donné?

Je veux appeler ma méthode générique avec un objet type donné.

void Foo(Type t)
{
     MyGenericMethod<t>();
}

ne fonctionne évidemment pas.

Comment puis-je le faire fonctionner?

50
codymanix

Votre exemple de code ne fonctionnera pas, car la méthode générique attend un identificateur de type, pas une instance de la classe Type. Vous devrez utiliser la réflexion pour le faire:

public class Example {

    public void CallingTest()
    {
        MethodInfo method = typeof (Example).GetMethod("Test");
        MethodInfo genericMethod = method.MakeGenericMethod(typeof (string));
        genericMethod.Invoke(this, null);

    }

    public void Test<T>()
    {
        Console.WriteLine(typeof (T).Name);
    }
}

Gardez à l'esprit que cela est très fragile, je suggère plutôt de trouver un autre modèle pour appeler votre méthode.

Une autre solution hacky (peut-être que quelqu'un peut le rendre un peu plus propre) serait d'utiliser une magie d'expression:

public class Example {

    public void CallingTest()
    {
        MethodInfo method = GetMethod<Example>(x => x.Test<object>());
        MethodInfo genericMethod = method.MakeGenericMethod(typeof (string));
        genericMethod.Invoke(this, null);

    }

    public static MethodInfo GetMethod<T>(Expression<Action<T>> expr)
    {
        return ((MethodCallExpression) expr.Body)
            .Method
            .GetGenericMethodDefinition();
    }

    public void Test<T>()
    {
        Console.WriteLine(typeof (T).Name);
    }
}

Notez le passage de l'identifiant de type "objet" comme argument de type générique dans le lambda. Impossible de comprendre si rapidement comment contourner cela. De toute façon, je pense que c'est sûr au moment de la compilation. Il se sent juste mal en quelque sorte: /

56
Erik van Brakel

Vous devez malheureusement utiliser la réflexion (pour les raisons mentionnées par Jared). Par exemple:

MethodInfo method = typeof(Foo).GetMethod("MyGenericMethod");
method = method.MakeGenericMethod(t);
method.Invoke(this, new object[0]);

Évidemment, vous voudriez plus de vérification d'erreur en réalité :)


Note latérale: mon MSDN local ne spécifie pas que le paramètre de MakeGenericMethod est un tableau de paramètres, donc je m'attendais à exiger:

method = method.MakeGenericMethod(new Type[] { t });

mais il semble qu'il soit un tableau de paramètres en réalité, et les documentation MSDN en ligne sont d'accord. Impair.

17
Jon Skeet