2009-10-22 24 views
25

Tengo el siguiente código:Método Genérico Ejecutado con un tipo de ejecución

public class ClassExample 
{ 

    void DoSomthing<T>(string name, T value) 
    { 
     SendToDatabase(name, value); 
    } 

    public class ParameterType 
    { 
     public readonly string Name; 
     public readonly Type DisplayType; 
     public readonly string Value; 

     public ParameterType(string name, Type type, string value) 
     { 
      if (string.IsNullOrEmpty(name)) 
       throw new ArgumentNullException("name"); 
      if (type == null) 
       throw new ArgumentNullException("type"); 

      this.Name = name; 
      this.DisplayType = type; 
      this.Value = value; 
     } 
    } 

    public void GetTypes() 
    { 
     List<ParameterType> l = report.GetParameterTypes(); 

     foreach (ParameterType p in l) 
     { 
      DoSomthing<p.DisplayType>(p.Name, (p.DisplayType)p.Value); 
     } 

    } 
} 

Ahora, sé que no se puede realizar HacerAlgo() ¿Hay alguna otra manera de utilizar esta función?

Respuesta

29

Puede, pero implica reflexión, pero puede hacerlo.

typeof(ClassExample) 
    .GetMethod("DoSomething") 
    .MakeGenericMethod(p.DisplayType) 
    .Invoke(this, new object[] { p.Name, p.Value }); 

Esto se verá en la parte superior de la clase que contiene, obtener la información método, cree un método genérico con el tipo apropiado, entonces se puede llamar a Invoke en él.

+0

Solo una captura, p.Valor es una cadena por lo que la invocación fallará a menos que p.DisplayType sea typeof (cadena). – stevemegson

+1

vergüenza esta es la única solución, meh –

+1

Bueno, estoy pensando que puede usar dynamic en 4.0 e inferirá el tipo de argumento genérico correcto, pero no he tenido la oportunidad de verificarlo todavía. No es que esté haciendo algo diferente bajo las cubiertas que el código anterior, pero tal vez sí. –

5
this.GetType().GetMethod("DoSomething").MakeGenericMethod(p.Value.GetType()).Invoke(this, new object[]{p.Name, p.Value}); 

Debería funcionar.

3

Los tipos genéricos no se pueden especificar en el tiempo de ejecución de la forma en que le gustaría hacerlo aquí.

Las opciones más simples serían agregar una sobrecarga no genérica de DoSomething, o simplemente llamar a DoSomething<object> e ignorar p.DisplayType. A menos que SendToDatabase dependa del tipo en tiempo de compilación tipo value (y probablemente no debería), no debería haber nada de malo en darle un object.

Si no puede hacer eso, tendrá que llamar al DoSomething usando reflexión, y obtendrá un gran golpe de rendimiento.

1

Estrictamente diciendo que puedes usar MethodInfo.MakeGenericMethod para esto.

Pero recomiendo cambiar DoSomething a una forma no genérica en su lugar, ya que no es evidente si realmente debe ser genérico.

+0

Acabo de simplificar el programa para la explicación. Esta es en realidad la solución más elegante, lo creas o no. :) ¡Gracias! – Sarit

3

Primero necesitamos para convertir p.Value al tipo correcto, ya que incluso si conocemos el tipo en tiempo de compilación no podemos pasar la cadena recta con el método ...

DoSomething<Int32>("10"); // Build error 

Para tipos numéricos simples y DateTime, podemos utilizar

object convertedValue = Convert.ChangeType(p.Value, p.DisplayType); 

Ahora podemos utilizar la reflexión para invocar el método genérico requerido ...

typeof(ClassExample) 
    .GetMethod("DoSomething") 
    .MakeGenericMethod(p.DisplayType) 
    .Invoke(this, new object[] { p.Name, convertedValue }); 
Cuestiones relacionadas