2012-09-29 14 views
6

me gustaría hacer algo como esto¿Cómo comprobar si un tipo T de un método genérico es IEnumerable <> y repetirlo?

void DoSomething<T>(T param) 
{ 
    if param is IEnumerable<?> 
    { 
     loop param and do stuff 
    } 
} 

no sé qué hacer en el lugar del signo de interrogación. ¿Y es posible en absoluto?

+0

Si 'param' no es del tipo' 'IEnumerable , qué quiere hacer nada? Si no, ¿por qué no restringir 'T' para que sea del tipo' IEnumerable 'con [where] (http://msdn.microsoft.com/en-us/library/bb384067.aspx)? –

+0

posibles respuestas aquí: http://stackoverflow.com/questions/1846671/determine-if-collection-is-of-type-ienumerablet –

+0

respuesta en el post desbordamiento de pila [haga clic aquí] [1] [1]: http://stackoverflow.com/questions/906499/getting-type-t-from-ienumerablet –

Respuesta

7

Lo que se busca es:

if (T is IEnumerable) { .. } 

pero si usted espera T para ser IEnumerable todo el tiempo que puede hacer:

void DoSomething<T>(T param) where T : IEnumerable 
{ 
    foreach (var t in param) { ... } 
} 

o control del tipo de los valores dentro de la IEnumerable :

public void DoSomething<T,U>(T val) where T : IEnumerable<U> 
{ 
    foreach (U a in val) 
    { 
    } 
} 

sin tener que preocuparse de comprobar por sí mismo, el compilador lo hará por ti, lo cual es una de las cosas buenas de tener un sistema de tipo estático y el compilador :)

+0

creo que en realidad trata de comprobar que el IEnumerable de un tipo específico, no solo un IEnumerable general. el enlace en el comentario bajo la pregunta maneja ese escenario –

+0

Buen punto. Completaré la respuesta con ese escenario, gracias. –

+0

Gracias por la buena respuesta. El problema es que no espero que T sea IEnumerable todo el tiempo. De hecho, ya tengo un método 'void ProcessList (lista IEnumerable )' y quiero reutilizarlo en 'DoSomething()' si el argumento es un IEnumerable. – tranmq

0

Hay algunas maneras:

void DoSomething<T>(T param) 
{ 
    if (param is IEnumerable) 
    { 
     foreach (var item in (IEnumerable)param) 
     { 
      // Do something 
     } 
    } 
} 

void DoSomething<T>(T param) 
{ 
    if (param is IEnumerable<string>) 
    { 
     foreach (var item in (IEnumerable<string>)param) 
     { 
      // Do something 
     } 
    } 
} 

void DoSomething<T,TItem>(T param) 
{ 
    if (param is IEnumerable<TItem>) 
    { 
     foreach (var item in (IEnumerable<TItem>)param) 
     { 
      // Do something 
     } 
    } 
} 
+0

La mejor práctica es usar 'as' en lugar de' is'-plus-direct-cast, ya que 'as' hace la costosa verificación de tipo de tiempo de ejecución solo una vez, mientras que is-plus-direct-cast lo hace dos veces. – phoog

0

Usted tiene que comprobar el tipo genérico abierto de cada interfaz que implementa la clase, como por lo que:

bool implements = typeof(T).GetInterfaces().Where(t => t.IsGenericType && 
    t.GetGenericTypeDefinition() == typeof(IEnumerable<>)).Any(); 

Esto le permitirá determinar si es o no un tipo implementa IEnumerable<T> sin saber realmente lo que es el tipo T. Recuerde que el tipo puede implementar IEnumerable<T> varias veces.

Si simplemente desea la secuencia de tipos que son parámetros de tipo para IEnumerable<T>, puede cambiar la consulta anterior a;

IEnumerable<Type> types = typeof(T).GetInterfaces(). 
    Where(t => t.IsGenericType && 
     t.GetGenericTypeDefinition() == typeof(IEnumerable<>)). 
    Select(t => t.GetGenericArguments()[0]); 
+0

Un tipo que implementa 'IEnumerable ' varias veces es realmente un tipo aterrador. – phoog

Cuestiones relacionadas