Risposte:
Se vuoi verificare se si tratta di un'istanza di tipo generico:
return list.GetType().IsGenericType;
Se vuoi verificare se è un generico List<T>
:
return list.GetType().GetGenericTypeDefinition() == typeof(List<>);
Come sottolinea Jon, questo controlla l'esatta equivalenza del tipo. Restituire false
non significa necessariamente list is List<T>
restituire false
(cioè l'oggetto non può essere assegnato a una List<T>
variabile).
Presumo che tu non voglia solo sapere se il tipo è generico, ma se un oggetto è un'istanza di un particolare tipo generico, senza conoscere gli argomenti del tipo.
Purtroppo non è terribilmente semplice. Non è male se il tipo generico è una classe (come in questo caso) ma è più difficile per le interfacce. Ecco il codice per una 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: come notato nei commenti, questo potrebbe funzionare per le interfacce:
foreach (var i in type.GetInterfaces())
{
if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType)
{
return true;
}
}
Ho un sospetto furbo che ci possano essere alcuni casi imbarazzanti attorno a questo, ma non riesco a trovarne uno per cui non riesca ora.
List<T>
in un modo o nell'altro. Se includi interfacce, è davvero complicato.
IsInstanceOfGenericType
con una chiamata a IsAssignableFrom
anziché l'operatore di uguaglianza ( ==
)?
Puoi usare un codice più breve usando l'althougth dinamico, questo potrebbe essere più lento della pura riflessione:
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();
Questi sono i miei due metodi di estensione preferiti che coprono la maggior parte dei casi limite di controllo del tipo generico:
Lavora con:
Presenta un sovraccarico che "esclude" il tipo generico specifico se restituisce true (vedere 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<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;