2011-08-12 17 views
5

Tengo un método que toma un parámetro genérico T. Internamente, para decidir qué otros métodos llamar, necesito saber (sin restringirlo) si ese parámetro es una Lista o simplemente algo.¿Mi tipo genérico es una lista o solo un artículo?

¿Cómo puedo hacer eso?

He estado usando

var isList = typeof(T).Name.ToLower().Contains("list`1"); 

pero que se siente como un enfoque sucio. ¿Qué es más limpio?

+0

¿Intentó compararlo con otro tipo de objeto de lista? – krs1

+1

Esto fallará si le pasa una instancia 'NotRealAList '. –

+0

¿Qué * exactamente * quieres decir cuando dices "lista"? ¿Te refieres al tipo exacto 'System.Collections.Generic.List '? ¿O te refieres a algo con 0 o más elementos? ¿O cualquier tipo de colección que se pueda leer y actualizar? etc. – stakx

Respuesta

11
var type = typeof(T); 
bool isList = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>); 

Si usted no necesita una coincidencia exacta de la lista, es posible que también acaba de comprobar si typeof(IList).IsAssignableFrom(typeof(T)), que muchas colecciones de listas como implementar.


Si quieres apoyar t igual a IList<T2> directamente (por lo que el parámetro de tipo T es una interfaz), entonces usted necesita para comprobar que por separado (GetGenericTypeDefinition() también podría volver typeof(IList<>)).

Si desea admitir cualquier tipo T que herede de cualquier IList<>, entonces tiene que ser un poco más creativo. Debe enumerar todas las interfaces, verificar si son genéricas (como se indicó anteriormente) y luego verificar si el tipo genérico de la interfaz es IList<>. Además, dado que GetInterfaces() realiza una llamada en Type solo devuelve las interfaces de nivel superior, necesita navegar a través de todas las interfaces implementadas por cada interfaz (recursivamente), para verificarlas también. Feo, lo sé.

+1

+1 porque responde a la pregunta. Como nota al margen, si hay alguna funcionalidad común seguida de la reflexión para un procesamiento posterior basado en el tipo, es posible que desee implementar un método 'Proceso (Lista elemento)' con sobrecargas para cada posibilidad. Deje que el compilador maneje el procesamiento posterior sin reflexión. Aunque, esto puede no ser aplicable en esta situación (no está claro si 'List ' es la única otra posibilidad). –

+0

Me gusta lo que obtienes en el fragmento de código, pero me estoy poniendo falso cada vez. Estoy pasando un IList como T, y sigo fallando. El segundo enfoque me da los mismos problemas. – reallyJim

+0

Aceptando esta y la respuesta, ya que responde completamente mi pregunta y resuelve mi problema, cubriendo la enumeración de las interfaces para encontrar IList <>. ¡Gracias! – reallyJim

0

Comprueba si implementa la interfaz IEnumerable.

bool isList = T is IEnumerable; 

Esto también devolverá verdadero si T es una pila, Array, o de otro tipo de cosas, pero creo que va a ser suficiente para sus propósitos.

+0

Esto no se compilará. – Gabe

+0

Esto no se compilará. 'T' es un 'parámetro de tipo' pero se usa como una variable. – reallyJim

+0

Necesita agregar 'typeof (T)' como en mi ejemplo. – Gabe

2

Bueno, siempre puedes usar typeof(T) y la palabra clave is, pero me gustaría echarle un vistazo a tu diseño.

Su enfoque realmente está derrotando el propósito de un método genérico. Si tiene que verificar el tipo de argumento genérico, bueno, su método no es genérico. Los genéricos son geniales para escenarios en los que no le importa cuál es el tipo subyacente. Si te importa, entonces el método no debe ser genérico, debería estar sobrecargado (probablemente). ¿Hasta qué punto nos dice lo que en realidad está tratando de lograr aquí para que podamos dar más respuestas útiles?

+0

Realmente no quieres saber. :) Estoy creando un objeto de consulta base con un método para llamar a ISqlQuery.List() o ISqlQuery.UniqueResult de NHibernate, devolviendo los resultados del SPROC como un tipo dinámico. En lugar de tomar el enfoque de "saber" de antemano y pedirle al código de llamada que llame "solo" o "lista", quiero ayudar a los desarrolladores tomando esa decisión al final. – reallyJim

+1

@reallyJim: un poco como [Massive] (https://github.com/robconery/massive)? –

+0

@jim Schubert Sí, no me había dado cuenta de que estaba tan cerca de reinventar la rueda. La raíz del problema es que tengo que ocuparme de los SPROC que arrojan resultados que necesito convertir a mis objetos comerciales, pero no quiero crear mapeos. – reallyJim

0

Si está buscando una colección integrada, debería marcar IEnumerable. De esta forma, no necesita preocuparse por el parámetro de tipo. Sin embargo, esto plantea un problema porque string implementa IEnumerable. Por lo tanto, necesitaría un código como este:

if (typeof(T) is string) { 
} else if (typeof(T) is IEnumerable) { 
} else { // its something else 
} 
+0

Dependiendo de la comprensión de lo que significa una lista, 'IEnumerable' podría cubrir demasiadas cosas. Por ejemplo, a diferencia de 'IList', un' IEnumerable' en sí mismo es exclusivamente de solo lectura: podría, por ej. implementar una clase 'IEnumerable' que devuelve la serie de Fibonacci. ¿Consideraría una instancia de esa clase una lista? – stakx

+0

@stakx - buen punto, actualicé mi respuesta. –

Cuestiones relacionadas