2010-12-15 31 views
23

¿Cuál sería la mejor manera de obtener el tipo de artículos que contiene una lista genérica? Es bastante fácil tomar el primer elemento de la colección y llamar a .GetType(), pero no siempre puedo estar seguro de que haya un elemento en la colección.C# - Obtenga el tipo de elemento para una lista genérica

Espero que tenga sentido.

Gracias,
Sonny

+0

¿Qué sabe usted acerca del tipo ya? ¿Podría proporcionar un contexto de muestra? –

Respuesta

51

Usted puede utilizar el método Type.GetGenericArguments para este propósito.

List<Foo> myList = ... 

Type myListElementType = myList.GetType().GetGenericArguments().Single(); 
+0

Lamentamos que esto esté un poco fuera del tema, pero ¿cómo obtuviste la coloración de la sintaxis en tu código? :) – Mehrdad

+1

Si el token 'T' está en el ámbito (por ejemplo, en un método que acepta una' Lista '), también puede usar' typeof (T) '. Si la 'Lista ' está almacenada en una variable de tipo 'object', tendrá que usar el enfoque anterior. – cdhowie

+0

¿No respondiste a otra pregunta, casi exactamente igual, el día de hoy? – LukeH

5
list.GetType().GetGenericArguments()[0] 
+1

ver mi edición. Y vea http://stackoverflow.com/editing-help – jjnguy

+0

¡Gracias! ¡Eso es realmente útil! – Mehrdad

6

Para un enfoque más robusto:

public static Type GetListType(object someList) 
{ 
    if (someList == null) 
     throw new ArgumentNullException("someList"); 

    var type = someList.GetType(); 

    if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(List<>)) 
     throw new ArgumentException("someList", "Type must be List<>, but was " + type.FullName); 

    return type.GetGenericArguments()[0]; 
} 

Pero si la variable se escribe List<T> a continuación, puedes utilizar typeof(T). Por ejemplo:

public static Type GetListType<T>(List<T> someList) 
{ 
    return typeof(T); 
} 

Tenga en cuenta que usted no necesita en realidad ni siquiera el parámetro someList. Este método es solo un ejemplo de cómo puede usar typeof si ya se encuentra en un método genérico. Solo necesita utilizar el enfoque de reflexión si no tiene acceso al token T (la lista se almacena en una variable no genérica, como la que se escribe IList, object, etc.).

+0

Holy cow, nice error handling. Es posible que desee agregar texto de error localizable también. ;) – Mehrdad

+0

@Lambert: Lo dejo como un ejercicio para el lector. :) – cdhowie

0
Public Shared Function ListItemType(ListType As System.Type) As System.Type 

    If Not ListType.IsGenericType Then 
    If ListType.BaseType IsNot Nothing AndAlso ListType.BaseType.IsGenericType Then 
     Return ListItemType(ListType.BaseType) 
    End If 
    Else 
    Return ListType.GetGenericArguments.Single 
    End If 
End Function 
1

¿Qué hay de esto, su todo estáticos (por ejemplo, no hay casos necesarios), y rápido (no hay bucles, sin el uso de LINQ), y es simple :) éstos trabajan para las colecciones:

[System.Diagnostics.DebuggerHidden] 
    public static Type GetIndexedType(this ICollection poICollection) 
    { 
     PropertyInfo oPropertyInfo = poICollection == null ? null : poICollection.GetType().GetProperty("Item"); 
     return oPropertyInfo == null ? null : oPropertyInfo.PropertyType; 
    } 

    [System.Diagnostics.DebuggerHidden] 
    public static Type GetEnumeratedType(this ICollection poICollection) 
    { 
     PropertyInfo oPropertyInfo = poICollection == null ? null : poICollection.GetType().GetMethod("GetEnumerator").ReturnType.GetProperty("Current"); 
     return oPropertyInfo == null ? null : oPropertyInfo.PropertyType; 
    } 

y algunas pruebas de unidades simples:

 [Test] 
     public void GetIndexedType() 
     { 
      Assert.AreEqual(null, ((ICollection)null).GetIndexedType()); 
      Assert.AreEqual(typeof(int), (new List<int>()).GetIndexedType()); 
      Assert.AreEqual(typeof(bool), (new SortedList<string, bool>()).GetIndexedType()); 
     } 

     [Test] 
     public void GetEnumeratedType() 
     { 
      Assert.AreEqual(null, ((ICollection)null).GetEnumeratedType()); 
      Assert.AreEqual(typeof(int), (new List<int>()).GetEnumeratedType()); 
      Assert.AreEqual(typeof(KeyValuePair<string, bool>), (new SortedList<string, bool>()).GetEnumeratedType()); 
     } 

Aviso el hecho de que hay dos maneras de ver esto, un tipo pueden ser devueltos por el indexador y otro tipo pueden ser devueltos por el encuestador. La prueba unitaria muestra ambos.

Diviértete, Frans.

P.s. Para enumerables:

[System.Diagnostics.DebuggerHidden] 
    public static Type GetEnumeratedType(this System.Collections.IEnumerable poIEnumerable) 
    { 
     PropertyInfo oPropertyInfo = poIEnumerable == null ? null : poIEnumerable.GetType().GetMethod("GetEnumerator").ReturnType.GetProperty("Current"); 
     return oPropertyInfo == null ? null : oPropertyInfo.PropertyType; 
    } 

Y para empadronador:

[System.Diagnostics.DebuggerHidden] 
    public static Type GetEnumeratedType(this System.Collections.IEnumerator poIEnumerator) 
    { 
     PropertyInfo oPropertyInfo = poIEnumerator == null ? null : poIEnumerator.GetType().GetProperty("Current"); 
     return oPropertyInfo == null ? null : oPropertyInfo.PropertyType; 
    } 
+0

Aquí sus métodos aceptan las versiones no genéricas de cada interfaz, pero solo funcionarán según lo previsto si de hecho implementan las versiones genéricas. Si va a tener esos requisitos, también puede hacer que los métodos acepten versiones genéricas de las interfaces directamente. – Servy

+0

Omg, esto funciona. –

4

Ésta es otra manera que trabaja para las colecciones no genéricas, también:

static Type GetItemType(Type collectionType) 
{ 
    return collectionType.GetMethod("get_Item").ReturnType; 
} 

Es decir, obtener el tipo de retorno de foo[x] , donde foo es del tipo especificado.

Ejemplos:

// Generic type; prints System.Int32 
Console.WriteLine(GetItemType(typeof(List<int>))); 

// Non-generic type; prints System.String 
Console.WriteLine(GetItemType(typeof(System.Collections.Specialized.StringCollection))); 

GetItemType El método anterior tiene un par de problemas, sin embargo:

  • Se lanza una NullReferenceException si el tipo tiene ningún operador de indexación.

  • lanza una AmbiguousMatchException si el tipo tiene varios sobrecargas para el operador de indexación (por ejemplo this[string] y this[int]).

Aquí es una versión más refinada:

public static Type GetItemType(this Type collectionType) 
{ 
    var types = 
     (from method in collectionType.GetMethods() 
     where method.Name == "get_Item" 
     select method.ReturnType 
     ).Distinct().ToArray(); 
    if (types.Length == 0) 
     return null; 
    if (types.Length != 1) 
     throw new Exception(string.Format("{0} has multiple item types", collectionType.FullName)); 
    return types[0]; 
} 
0

nuevo método cuestión antiguo con dynamic

void Foo(){ 
    Type type GetTypeT(data as dynamic); 
} 

private static Type GetTypeT<T>(IEnumerable<T> data) 
{ 
    return typeof(T); 
} 
0
public Type GetType(IEnumerable<object> resultList) 
    { 
     return resultList.GetType().GetElementType(); 
    } 
+0

Si bien este fragmento de código puede resolver la pregunta, [incluyendo una explicación] (// meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) realmente ayuda a mejorar la calidad de su publicación. Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. Por favor, intente no saturar su código con comentarios explicativos, ya que esto reduce la legibilidad tanto del código como de las explicaciones. – FrankerZ

Cuestiones relacionadas