Réponses:
Si vous voulez vérifier s'il s'agit d'une instance d'un type générique:
return list.GetType().IsGenericType;
Si vous voulez vérifier s'il s'agit d'un générique List<T>
:
return list.GetType().GetGenericTypeDefinition() == typeof(List<>);
Comme le souligne Jon, cela vérifie l'équivalence de type exacte. Un retour false
ne signifie pas nécessairement un list is List<T>
retour false
(c'est-à-dire que l'objet ne peut pas être affecté à une List<T>
variable).
Je suppose que vous ne voulez pas seulement savoir si le type est générique, mais si un objet est une instance d'un type générique particulier, sans connaître les arguments de type.
Ce n'est malheureusement pas très simple. Ce n'est pas trop mal si le type générique est une classe (comme c'est le cas dans ce cas) mais c'est plus difficile pour les interfaces. Voici le code d'une classe:
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<string>()));
// 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<int>()));
}
class SubList : List<string>
{
}
class SubList<T> : List<T>
{
}
}
EDIT: Comme indiqué dans les commentaires, cela peut fonctionner pour les interfaces:
foreach (var i in type.GetInterfaces())
{
if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType)
{
return true;
}
}
J'ai un soupçon sournois qu'il peut y avoir des cas délicats à ce sujet, mais je ne peux pas en trouver un pour lequel il échoue pour le moment.
List<T>
sous une forme ou une autre. Si vous incluez des interfaces, c'est vraiment délicat.
IsInstanceOfGenericType
par un appel à IsAssignableFrom
au lieu de l'opérateur d'égalité ( ==
)?
Vous pouvez utiliser du code plus court en utilisant dynamique bien que cela puisse être plus lent que la réflexion pure:
public static class Extension
{
public static bool IsGenericList(this object o)
{
return IsGeneric((dynamic)o);
}
public static bool IsGeneric<T>(List<T> o)
{
return true;
}
public static bool IsGeneric( object o)
{
return false;
}
}
var l = new List<int>();
l.IsGenericList().Should().BeTrue();
var o = new object();
o.IsGenericList().Should().BeFalse();
Ce sont mes deux méthodes d'extension préférées qui couvrent la plupart des cas marginaux de vérification de type générique:
Marche avec:
A une surcharge qui `` sortira '' le type générique spécifique s'il renvoie true (voir le test unitaire pour des exemples):
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;
}
}
Voici un test pour démontrer la fonctionnalité (de base):
[Test]
public void SimpleGenericInterfaces()
{
Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IEnumerable<>)));
Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IQueryable<>)));
Type concreteType;
Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IEnumerable<>), out concreteType));
Assert.AreEqual(typeof(IEnumerable<string>), concreteType);
Assert.IsTrue(typeof(Table<string>).IsOfGenericType(typeof(IQueryable<>), out concreteType));
Assert.AreEqual(typeof(IQueryable<string>), concreteType);
}
return list.GetType().IsGenericType;