2009-09-10 24 views
46

Quiero llamar a mi método genérico con un objeto tipo dado.¿Cómo llamar al método genérico con un objeto Tipo dado?

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

obviamente no funciona.

¿Cómo puedo hacer que funcione?

+0

Solo porque es difícil de encontrar: Usar 'dynamic' te salva de todo el trabajo de reflexión propenso a errores. La mejor respuesta está en la pregunta a la que se hace referencia: http://stackoverflow.com/a/22441650/143684 – ygoe

Respuesta

48

Su muestra de código no funcionará, porque el método genérico espera un identificador de tipo, no una instancia de la clase Tipo. Vas a tener que utilizar la reflexión para hacerlo:

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

Tenga en cuenta que esto es muy frágil, y no me gustaría sugerir la búsqueda de otro patrón de llamar a su método.

Otra solución hacky (tal vez alguien puede hacer que sea un poco más limpia) sería utilizar alguna expresión mágica:

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

Nota pasando el identificador del tipo de 'objeto' como un argumento de tipo genérico en el lambda. No pude entender tan rápido cómo evitar eso. De cualquier forma, creo que esto es seguro en tiempo de compilación. Simplemente se siente mal de alguna manera:/

+0

¿Qué es el "Programa"? – codymanix

+0

Malo, cambié algunos nombres (probados en una aplicación de consola C# predeterminada, por lo que la clase se llama Programa;)) Se corrigió por usted, debería ser el nombre de la clase en la que desea llamar al método. –

+1

Gran idea con las expresiones. Tampoco puedo pensar en una forma de referirse a un método genérico sin especificar al menos un argumento ficticio genérico. – codymanix

-2

Este enfoque no funcionará. El motivo por el que Type es un objeto cuyo tipo se determina en tiempo de ejecución. Sin embargo, está tratando de usarlo para llamar a un método genérico. El tipo de una llamada de método genérico se establece en tiempo de compilación. Por lo tanto, un objeto Type no se puede usar nunca para un parámetro de tipo en un método genérico.

+2

¿Entonces cuál es la solución? También estoy en este tema tanto. Gracias. – Tarik

15

Tiene que usar la reflexión, desafortunadamente (por las razones mencionadas por Jared). Por ejemplo:

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

Obviamente te gustaría más la comprobación de errores en la realidad :)


Nota al margen: mi MSDN local no especifica que el parámetro de MakeGenericMethod es una matriz de parámetros, por lo me hubiera esperado a requerir:

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

pero parece que es una matriz de parámetros en la realidad, y la online MSDN docs de acuerdo. Impar.

+1

argghh! El Skeet me ganó:/ –

+0

Gracias por responder, Jon. Pero ya he dado el método correcto, ¿por qué tengo que cargarlos por su nombre? ¿No hay una forma más segura que no involucre nombres de métodos como cadenas? – codymanix

+0

Cody: Agregué otra alternativa en mi respuesta (tratando de vencer a Skeet) que no involucra cadenas. No es tan limpio como quiero, pero la idea es clara, creo. –

Cuestiones relacionadas