2009-05-01 18 views
44

Tengo una clase (Un control web) que tiene una propiedad de tipo IEnumerable y me gustaría trabajar con el parámetro utilizando LINQ.Convertir/Convertir IEnumerable en IEnumerable <T>

¿Hay alguna forma de convertir/convertir/invocar a través de la reflexión a IEnumerable <T> sin conocer el tipo en tiempo de compilación?

Method void (IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 

    if (enumerator.MoveNext()) 
    { 
     var type = enumerator.Current.GetType(); 
     Method2<type>(source); // this doesn't work! I know! 
    } 
} 

void Method2<T>(IEnumerable<T> source) {} 

Respuesta

56

¿Su Method2 me importa qué tipo se pone? Si no es así, usted podría llamar Cast<object>():

void Method (IEnumerable source) 
{ 
    Method2(source.Cast<object>()); 
} 

Si definitivamente necesidad de conseguir el tipo correcto, tendrá que utilizar la reflexión.

Algo así como:

MethodInfo method = typeof(MyType).GetMethod("Method2"); 
MethodInfo generic = method.MakeGenericMethod(type); 
generic.Invoke(this, new object[] {source}); 

No es lo ideal, aunque ..., en particular, si la fuente no es exactamente un IEnumerable<type> entonces la invocación se producirá un error. Por ejemplo, si el primer elemento es una cadena, pero la fuente es un List<object>, tendrá problemas.

+0

Dependiendo de la situación, también puede usar 'OfType', solo señalando. Vea también: http://stackoverflow.com/questions/4015930/when-to-use-cast-and-oftype-in-linq –

8

Es posible que desee refactorizar el código para utilizar IEnumerable.Cast<T>

utilizar de esta manera:

IEnumerable mySet = GetData(); 
var query = from x in mySet.Cast<int>() 
      where x > 2 
      select x; 
+0

Requiere el tipo en tiempo de compilación. Mismo problema. – andleer

+0

Eso es correcto. Y también lo hace Method2. Siempre se puede convertir a un IEnumerable ... –

2

Esto es años después, pero he resuelto el problema List<Object>.

void Method(IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 
    if (enumerator.MoveNext()) 
    { 
     MethodInfo method = typeof(MyClass).GetMethod("Method2"); 
     MethodInfo generic; 
     Type type = enumerator.Current.GetType(); 
     bool sameType = true; 

     while (enumerator.MoveNext()) 
     { 
      if (enumerator.Current.GetType() != type) 
      { 
       sameType = false; 
       break; 
      } 
     } 

     if (sameType) 
      generic = method.MakeGenericMethod(type); 
     else 
      generic = method.MakeGenericMethod(typeof(object)); 

     generic.Invoke(this, new object[] { source }); 
    } 
} 
3

Con .NET 4 sólo puede emitir source a dynamic antes de pasarlo al método. Esto hará que la sobrecarga genérica correcta para ser resuelto en tiempo de ejecución sin ningún código reflexión fea:

void Method(IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 

    if (enumerator.MoveNext()) 
    { 
     Method2((dynamic)source); 
    } 
} 

Al igual que con la segunda solución de Jon, esto sólo funcionará si su origen es en realidad un IEnumerable<T>. Si se trata de una llanura IEnumerable entonces usted tendrá que crear otro método que convierte a la correcta IEnumerable<T> tipo, como en la siguiente solución:

IEnumerable<T> Convert<T>(IEnumerable source, T firstItem) 
{ 
    // Note: firstItem parameter is unused and is just for resolving type of T 
    foreach(var item in source) 
    { 
     yield return (T)item; 
    } 
} 

void Method(IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 

    if (enumerator.MoveNext()) 
    { 
     dynamic firstItem = enumerator.Current; 
     dynamic typedEnumerable = Convert(source, firstItem); 
     Method2(typedEnumerable); 
    } 
} 
Cuestiones relacionadas