The previously accepted answer es agradable pero es un error. Afortunadamente, el error es pequeño. La comprobación de IEnumerable
no es suficiente si realmente desea conocer la versión genérica de la interfaz; hay muchas clases que implementan solo la interfaz no genérica. Daré la respuesta en un minuto. Primero, sin embargo, me gustaría señalar que la respuesta aceptada es demasiado complicado, ya que el código siguiente lograría el mismo bajo las circunstancias dadas:
if (items[key] is IEnumerable)
Esto hace aún más, ya que funciona para cada artículo por separado (y no en su subclase común, V
).
Ahora, para la solución correcta. Esto es un poco más complicado ya que hay que tomar el tipo genérico IEnumerable`1
(es decir, el tipo IEnumerable<>
con un parámetro de tipo) e inyectar el argumento genérico derecha:
static bool IsGenericEnumerable(Type t) {
var genArgs = t.GetGenericArguments();
if (genArgs.Length == 1 &&
typeof(IEnumerable<>).MakeGenericType(genArgs).IsAssignableFrom(t))
return true;
else
return t.BaseType != null && IsGenericEnumerable(t.BaseType);
}
Puede probar la exactitud de este código con facilidad :
var xs = new List<string>();
var ys = new System.Collections.ArrayList();
Console.WriteLine(IsGenericEnumerable(xs.GetType()));
Console.WriteLine(IsGenericEnumerable(ys.GetType()));
rendimientos:
True
False
no se preocupe demasiado por el hecho de que este utiliza la reflexión. Si bien es cierto que esto agrega sobrecarga de tiempo de ejecución, también lo hace el uso del operador is
.
Por supuesto, el código anterior está terriblemente restringido y podría ampliarse a un método de aplicación más general, IsAssignableToGenericType
. La siguiente implementación es ligeramente incorrecta y la dejo aquí solo para fines históricos. No lo use.En su lugar, James has provided an excellent, correct implementation in his answer.
public static bool IsAssignableToGenericType(Type givenType, Type genericType) {
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
if (it.IsGenericType)
if (it.GetGenericTypeDefinition() == genericType) return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return baseType.IsGenericType &&
baseType.GetGenericTypeDefinition() == genericType ||
IsAssignableToGenericType(baseType, genericType);
}
falla cuando el genericType
es lo mismo que givenType
; por la misma razón, se produce un error de tipos anulables, es decir
IsAssignableToGenericType(typeof(List<int>), typeof(List<>)) == false
IsAssignableToGenericType(typeof(int?), typeof(Nullable<>)) == false
He creado un gist with a comprehensive suite of test cases.
Esto es exactamente lo que estaba buscando. ¡Gracias! Todavía usa reflexión, pero estaba buscando la sintaxis "typeof (IEnumerable <>)". ¡Gracias! –
¿No hay otra forma de hacer la verificación del tipo, que no sea el uso de "es"? –
la última línea debería leer 'return (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == genericType) || IsAssignableToGenericType (baseType, genericType); 'No puede evitar la recursividad solo porque la clase base es genérica. –