Prueba si el objeto es de tipo genérico en C #

Me gustaría realizar una prueba si un objeto es de un tipo genérico. Intenté lo siguiente sin éxito:

public bool Test() { List list = new List(); return list.GetType() == typeof(List); } 

¿Qué estoy haciendo mal y cómo realizo esta prueba?

Si desea verificar si se trata de una instancia de un tipo genérico:

 return list.GetType().IsGenericType; 

Si desea verificar si se trata de una List genérica List :

 return list.GetType().GetGenericTypeDefinition() == typeof(List<>); 

Como Jon señala, esto verifica la equivalencia de tipo exacta. Devolver false no significa necesariamente que la list is List devuelve false (es decir, el objeto no puede asignarse a una variable de List ).

Supongo que no solo quiere saber si el tipo es genérico, sino si un objeto es una instancia de un tipo genérico particular, sin conocer los argumentos de tipo.

No es terriblemente simple, desafortunadamente. No es tan malo si el tipo genérico es una clase (como lo es en este caso), pero es más difícil para las interfaces. Aquí está el código para una clase:

 using System; using System.Collections.Generic; using System.Reflection; class Test { static bool IsInstanceOfGenericType(Type genericType, object instance) { Type type = instance.GetType(); while (type != null) { if (type.IsGenericType && type.GetGenericTypeDefinition() == genericType) { return true; } type = type.BaseType; } return false; } static void Main(string[] args) { // True Console.WriteLine(IsInstanceOfGenericType(typeof(List<>), new List())); // False Console.WriteLine(IsInstanceOfGenericType(typeof(List<>), new string[0])); // True Console.WriteLine(IsInstanceOfGenericType(typeof(List<>), new SubList())); // True Console.WriteLine(IsInstanceOfGenericType(typeof(List<>), new SubList())); } class SubList : List { } class SubList : List { } } 

EDITAR: Como se señala en los comentarios, esto puede funcionar para las interfaces:

 foreach (var i in type.GetInterfaces()) { if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType) { return true; } } 

Tengo la sospecha de que puede haber algunos casos de borde incómodo alrededor de esto, pero no puedo encontrar uno por el que falla por ahora.

Puedes usar código más corto usando dinámica, aunque esto puede ser más lento que la reflexión pura:

 public static class Extension { public static bool IsGenericList(this object o) { return IsGeneric((dynamic)o); } public static bool IsGeneric(List o) { return true; } public static bool IsGeneric( object o) { return false; } } var l = new List(); l.IsGenericList().Should().BeTrue(); var o = new object(); o.IsGenericList().Should().BeFalse(); 

Estos son mis dos métodos de extensión favoritos que cubren la mayoría de los casos extremos de verificación de tipos generics:

Funciona con:

  • Múltiples interfaces (genéricas)
  • Múltiples clases base (genéricas)
  • Tiene una sobrecarga que ‘eliminará’ el tipo genérico concreto si devuelve verdadero (ver prueba unitaria para muestras):

     public static bool IsOfGenericType(this Type typeToCheck, Type genericType) { Type concreteType; return typeToCheck.IsOfGenericType(genericType, out concreteType); } public static bool IsOfGenericType(this Type typeToCheck, Type genericType, out Type concreteGenericType) { while (true) { concreteGenericType = null; if (genericType == null) throw new ArgumentNullException(nameof(genericType)); if (!genericType.IsGenericTypeDefinition) throw new ArgumentException("The definition needs to be a GenericTypeDefinition", nameof(genericType)); if (typeToCheck == null || typeToCheck == typeof(object)) return false; if (typeToCheck == genericType) { concreteGenericType = typeToCheck; return true; } if ((typeToCheck.IsGenericType ? typeToCheck.GetGenericTypeDefinition() : typeToCheck) == genericType) { concreteGenericType = typeToCheck; return true; } if (genericType.IsInterface) foreach (var i in typeToCheck.GetInterfaces()) if (i.IsOfGenericType(genericType, out concreteGenericType)) return true; typeToCheck = typeToCheck.BaseType; } } 

Aquí hay una prueba para demostrar la funcionalidad (básica):

  [Test] public void SimpleGenericInterfaces() { Assert.IsTrue(typeof(Table).IsOfGenericType(typeof(IEnumerable<>))); Assert.IsTrue(typeof(Table).IsOfGenericType(typeof(IQueryable<>))); Type concreteType; Assert.IsTrue(typeof(Table).IsOfGenericType(typeof(IEnumerable<>), out concreteType)); Assert.AreEqual(typeof(IEnumerable), concreteType); Assert.IsTrue(typeof(Table).IsOfGenericType(typeof(IQueryable<>), out concreteType)); Assert.AreEqual(typeof(IQueryable), concreteType); } 
 return list.GetType().IsGenericType;