Verifica se l’object è di tipo generico in C #

Vorrei eseguire un test se un object è di tipo generico. Ho provato il seguente senza successo:

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

Cosa sto sbagliando e come eseguo questo test?

Se si desidera verificare se si tratta di un’istanza di tipo generico:

 return list.GetType().IsGenericType; 

Se vuoi controllare se è un List generico List :

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

Come sottolinea Jon, questo controlla l’esatta equivalenza del tipo. Restituire false non significa necessariamente che l’ list is List restituisce false (ovvero l’object non può essere assegnato a una variabile List ).

Suppongo che tu non voglia solo sapere se il tipo è generico, ma se un object è un’istanza di un particolare tipo generico, senza conoscere gli argomenti di tipo.

Non è terribilmente semplice, sfortunatamente. Non è male se il tipo generico è una class (come in questo caso) ma è più difficile per le interfacce. Ecco il codice per una class:

 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 { } } 

EDIT: come notato nei commenti, questo può funzionare per le interfacce:

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

Ho un vago sospetto che ci possano essere alcuni casi imbarazzanti riguardo a questo, ma non riesco a trovarne uno che fallisce proprio adesso.

È ansible utilizzare un codice più breve utilizzando un’attenuazione dynamic che potrebbe essere più lenta del puro riflesso:

 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(); 

Questi sono i miei due metodi di estensione preferiti che coprono la maggior parte dei casi limite di controllo di tipo generico:

Lavora con:

  • Più interfacce (generiche)
  • Più classi di base (generiche)
  • Ha un sovraccarico che “fuori” il tipo generico concreto se restituisce true (vedi test unitario per i campioni):

     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; } } 

Ecco un test per dimostrare la funzionalità (di base):

  [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;