web-dev-qa-db-ja.com

特定のTypeオブジェクトでジェネリックメソッドを呼び出す方法は?

特定の型オブジェクトを使用して汎用メソッドを呼び出したい。

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

明らかに動作しません。

どうすればそれを機能させることができますか?

50
codymanix

ジェネリックメソッドはTypeクラスのインスタンスではなくタイプ識別子を要求するため、コードサンプルは機能しません。それを行うにはリフレクションを使用する必要があります。

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

これは非常に壊れやすいので、メソッドを呼び出す別のパターンを見つけることをお勧めします。

別のハッキングソリューション(誰かがそれを少しきれいにすることができるかもしれません)は、いくつかの表現の魔法を使用することです。

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

'object'型識別子をラムダのジェネリック型引数として渡すことに注意してください。どうやってそれを回避するかがすぐにわかりませんでした。いずれにせよ、これはコンパイル時に安全だと思います。それはどういうわけか間違っているように感じます:/

56
Erik van Brakel

残念ながら、リフレクションを使用する必要があります(Jaredが言及した理由のため)。例えば:

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

明らかに、実際にはより多くのエラーチェックが必要です:)


サイドノート:私のローカルMSDNは、MakeGenericMethodからのパラメーターがパラメーター配列であることを指定していないため、次のものが必要になると予想されていました。

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

しかし、は実際にはパラメータ配列であり、 オンラインMSDNドキュメント は一致しているようです。奇数。

17
Jon Skeet