2011-01-07 9 views
5

yo sepa this pregunta, y es el seguimiento, y también this uno, pero no puedo ponerlos juntos de una manera que ayudará a hacer lo que quiero hacer:Cómo detectar si T es IEnumerable <T2>, y si es así, ¿obtener tipo de T2?

tengo una tipo genérico, y quiero comprobar que T es un struct O si implementa IEnumerable<T2>, entonces me gustaría comprobar que T2 es un struct.

Hasta ahora, Tengo que aquí ('scuse el código rudimentario, esto es experimental):

private class TestClass<T> 
{ 
    public TestClass() 
    { 
     Type type = typeof(T); 
     //(detecting T == IEnumerable<something> ommitted for clarity) 
     Type enumerableType = type.GetInterfaces() 
       .Where(t => t.IsGenericType) 
       .Select(t => t.GetGenericTypeDefinition()) 
       .Where(t => t == typeof(IEnumerable<>)) 
       .FirstOrDefault(); 
     if(enumerableType != null) 
     { 
      Type enumeratedType = type.GetGenericArguments().First(); 
      if(!enumeratedType.IsValueType) //throw etc... 
     } 
    } 
} 

El problema que tengo es que es enumerableTypeIEnumerable<>, por lo que el enumeratedType sale como T, no lo que sea que haya pasado (por ejemplo, new TestClass<int[]>()).

Respuesta

4

Su problema es que ha seleccionado el tipo que tiene todos los datos a favor de su plantilla de tipo genérico borrada.

Probar:

Type enumerableType = type.GetInterfaces() 
      .Where(t => t.IsGenericType) 
      .Where(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>)) 
      .Select(t => t.GetGenericArguments()[0]) 
      .FirstOrDefault(); 
+0

Gracias, funciona, y confiaré en ti para los casos extremos (un poco fuera de mi alcance en los comentarios sobre la respuesta de dtb). – Benjol

+0

@Benjol: Dependiendo de la versión de .NET que esté utilizando, es posible que también desee una comprobación explícita de las matrices, ya que [en .NET 2.0 'GetInterfaces' se rompió en los tipos de matriz] (https://connect.microsoft. com/VisualStudio/feedback/details/93995/getinterfaces-bug-for-typed-array). dtb tiene esa prueba en particular correcta ... 'if (type.IsArray) return type.GetElementType();'. –

2

De Matt Warren's Blog:

internal static class TypeSystem { 
    internal static Type GetElementType(Type seqType) { 
     Type ienum = FindIEnumerable(seqType); 
     if (ienum == null) return seqType; 
     return ienum.GetGenericArguments()[0]; 
    } 
    private static Type FindIEnumerable(Type seqType) { 
     if (seqType == null || seqType == typeof(string)) 
      return null; 
     if (seqType.IsArray) 
      return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType()); 
     if (seqType.IsGenericType) { 
      foreach (Type arg in seqType.GetGenericArguments()) { 
       Type ienum = typeof(IEnumerable<>).MakeGenericType(arg); 
       if (ienum.IsAssignableFrom(seqType)) { 
        return ienum; 
       } 
      } 
     } 
     Type[] ifaces = seqType.GetInterfaces(); 
     if (ifaces != null && ifaces.Length > 0) { 
      foreach (Type iface in ifaces) { 
       Type ienum = FindIEnumerable(iface); 
       if (ienum != null) return ienum; 
      } 
     } 
     if (seqType.BaseType != null && seqType.BaseType != typeof(object)) { 
      return FindIEnumerable(seqType.BaseType); 
     } 
     return null; 
    } 
} 
+0

+1, todas las otras respuestas cometer el mismo error que no tienen, es decir, 't == typeof (IEnumerable <>)'. Eso nunca funcionará, ya que una instancia de ese tipo NUNCA puede existir. – leppie

+0

@leppie, uh, hablar de instancias de tipos me pone un poco peludo cuando se trata de la reflexión. ¿Estás diciendo que nunca puedes instanciar un objeto de tipo 'IEnumerable <>', o que nunca puedes tener 'typeof (T) == typeof (IEnumerable <>)' - como en 'typeof (IEnumerable ')? – Benjol

+0

@leppie: Mire más de cerca, se llama a GetGenericTypeDefinition() antes de la comparación, coincidirá. –

0

Creo que este código hace lo que quiere.
Sin embargo, es posible que desee limpiarlo un poco.

public class TestClass<T> 
{ 
    public TestClass() 
    { 
     bool hasStruct = false; 
     Type t1 = this.GetType().GetGenericArguments()[0]; 
     if(t1.IsValueType){ 
      hasStruct = true; 
     } 
     if (t1.IsGenericType) 
     { 
      Type t = t1.GetGenericArguments()[0]; 
      if (t.IsValueType) 
      { 
       hasStruct = true; 
      } 
     } 

    } 
} 
Cuestiones relacionadas