2009-06-25 25 views
88

Estoy trabajando en un proyecto de reflexión, y ahora estoy atascado. Si tengo un objeto de "myclass" que puede contener una lista ¿alguien sabe cómo obtener el tipo como en el siguiente código si la propiedad myclass.SomList está vacía?C# lista genérica <T> cómo obtener el tipo de T?

List<myclass> myList = dataGenerator.getMyClasses(); 
lbxObjects.ItemsSource = myList; 
lbxObjects.SelectionChanged += lbxObjects_SelectionChanged; 

private void lbxObjects_SelectionChanged(object sender, SelectionChangedEventArgs e) 
     { 
      Reflect(); 
     } 
Private void Reflect() 
{ 
foreach (PropertyInfo pi in lbxObjects.SelectedItem.GetType().GetProperties()) 
{ 
     switch (pi.PropertyType.Name.ToLower()) 
     { 
     case "list`1": 
      {   
      // This works if the List<T> contains one or more elements. 
      Type tTemp = GetGenericType(pi.GetValue(lbxObjects.SelectedItem, null)); 

      // but how is it possible to get the Type if the value is null? 
      // I need to be able to create a new object of the type the generic list expect. 
      // Type type = pi.getType?? // how to get the Type of the class inside List<T>? 
      break; 
      } 
     } 
} 
} 
private Type GetGenericType(object obj) 
     { 
      if (obj != null) 
      { 
       Type t = obj.GetType(); 
       if (t.IsGenericType) 
       { 
        Type[] at = t.GetGenericArguments(); 
        t = at.First<Type>(); 
       } return t; 
      } 
      else 
      { 
       return null; 
      } 
     } 

Respuesta

174
Type type = pi.PropertyType.PropertyType; 
if(type.IsGenericType && type.GetGenericTypeDefinition() 
     == typeof(List<>)) 
{ 
    Type itemType = type.GetGenericArguments()[0]; // use this... 
} 

De manera más general, para apoyar cualquier IList<T>, es necesario comprobar las interfaces:

foreach (Type interfaceType in type.GetInterfaces()) 
{ 
    if (interfaceType.IsGenericType && 
     interfaceType.GetGenericTypeDefinition() 
     == typeof(IList<>)) 
    { 
     Type itemType = type.GetGenericArguments()[0]; 
     // do something... 
     break; 
    } 
} 
+8

no debería ser Tipo itemtype = interfaceType.GetGenericArguments() [0]; – Muxa

+0

De manera divertida, el segundo ejemplo falla, digamos 'IList '. Reparar a continuación http://stackoverflow.com/a/13608408/284795 –

+0

Sé que la respuesta es muy antigua, pero trato de entender lo siguiente: 'GetGenericArguments() [0];' ¿por qué está el 0? ¿Hay siempre solo un elemento en el Tipo []? – Ismoh

7

la respuesta de Marc es el método que utilizo para esto, pero por simplicidad (y ¿una API más amigable?) puede definir una propiedad en la clase base de la colección si tiene una como:

public abstract class CollectionBase<T> : IList<T> 
{ 
    ... 

    public Type ElementType 
    { 
     get 
     { 
     return typeof(T); 
     } 
    } 
} 

He encontrado este enfoque útil, y es fácil de entender para cualquier recién llegado a los genéricos.

+0

Quería utilizar este enfoque, pero luego me di cuenta de que tendré que tener la instancia de lista para determinar el tipo de elemento, que no siempre tendré. – Muxa

+1

puede hacer la propiedad estática.Al igual que "tipo de elemento de tipo estático público" ... se obtiene como "var t = CollectionBase .ElementType;" ... no necesitará una variable de instancia – Nabheet

+0

Verdadero. Static le permite trabajar con una clase sin un objeto existente. Encuentro este enfoque más fácil de trabajar. Claro, necesita almacenar información adicional en sus objetos, pero al menos se ahorra en esta llamada en cascada en la respuesta aprobada. – rbaleksandar

4

Dado un objeto que sospecho que haber algún tipo de IList<>, ¿cómo puedo determinar de lo que se trata de unIList<>?

Aquí hay una solución confiable. Mis disculpas por la longitud: la API de introspección de C# hace que esto sea sorprendentemente difícil.

/// <summary> 
/// Test if a type implements IList of T, and if so, determine T. 
/// </summary> 
public static bool TryListOfWhat(Type type, out Type innerType) 
{ 
    Contract.Requires(type != null); 

    var interfaceTest = new Func<Type, Type>(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>) ? i.GetGenericArguments().Single() : null); 

    innerType = interfaceTest(type); 
    if (innerType != null) 
    { 
     return true; 
    } 

    foreach (var i in type.GetInterfaces()) 
    { 
     innerType = interfaceTest(i); 
     if (innerType != null) 
     { 
      return true; 
     } 
    } 

    return false; 
} 

Ejemplo de uso:

object value = new ObservableCollection<int>(); 
Type innerType; 
TryListOfWhat(value.GetType(), out innerType).Dump(); 
innerType.Dump(); 

devoluciones

True 
typeof(Int32) 
+0

No veo ningún otro resultado como método Marcs (también con marcs tengo Int32) – Offler

17

Dado un objeto que sospecho que haber algún tipo de IList<>, ¿cómo puedo determinar de lo es una IList<> ?

Aquí está la solución aguerrida. Supone que tiene el objeto real para probar (en lugar de Type). uso

public static Type ListOfWhat(Object list) 
{ 
    return ListOfWhat2((dynamic)list); 
} 

private static Type ListOfWhat2<T>(IList<T> list) 
{ 
    return typeof(T); 
} 

Ejemplo:

object value = new ObservableCollection<DateTime>(); 
ListOfWhat(value).Dump(); 

Prints

typeof(DateTime) 
+0

-1: ¿Por qué 'IList ' en lugar de 'IEnumerable '? ¿Por qué 'dinámico'? –

+0

¿He entendido mal la pregunta de OP? El detalle no estaba claro, así que respondí la pregunta en el título. –

+3

¡Usted señor, es un mago! Me he estado golpeando la cabeza tratando de resolver un problema con un analizador dinámico con una estructura de datos genérica (que puede tratar con tipos singulares y listas) y * esto * me puso en el camino correcto. –

Cuestiones relacionadas