Odpowiedzi:
Jeśli chcesz sprawdzić, czy jest to instancja typu ogólnego:
return list.GetType().IsGenericType;
Jeśli chcesz sprawdzić, czy jest to generyczny List<T>
:
return list.GetType().GetGenericTypeDefinition() == typeof(List<>);
Jak wskazuje Jon, sprawdza to dokładną równoważność typów. Powrót false
niekoniecznie oznacza list is List<T>
zwrot false
(tj. Obiekt nie może być przypisany do List<T>
zmiennej).
Zakładam, że nie chcesz tylko wiedzieć, czy typ jest ogólny, ale jeśli obiekt jest wystąpieniem określonego typu ogólnego, bez znajomości argumentów typu.
Niestety nie jest to strasznie proste. Nie jest źle, jeśli typ generyczny jest klasą (tak jak w tym przypadku), ale jest to trudniejsze w przypadku interfejsów. Oto kod zajęć:
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>
{
}
}
EDYCJA: Jak zauważono w komentarzach, może to działać w przypadku interfejsów:
foreach (var i in type.GetInterfaces())
{
if (i.IsGenericType && i.GetGenericTypeDefinition() == genericType)
{
return true;
}
}
Podejrzewam, że mogą być wokół tego jakieś niezręczne skrajne przypadki, ale nie mogę znaleźć takiego, który na razie zawodzi.
List<T>
w takiej czy innej formie. Jeśli dołączysz interfejsy, jest to naprawdę trudne.
IsInstanceOfGenericType
na wywołanie IsAssignableFrom
zamiast operatora równości ( ==
)?
Możesz użyć krótszego kodu, używając dynamicznego, chociaż może to być wolniejsze niż czyste odbicie:
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();
Oto moje dwie ulubione metody rozszerzeń, które obejmują większość przypadków skrajnych sprawdzania typów ogólnych:
Pracuje z:
Ma przeciążenie, które `` wyłączy '' określony typ ogólny, jeśli zwróci wartość true (zobacz test jednostkowy dla próbek):
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;
}
}
Oto test demonstrujący (podstawową) funkcjonalność:
[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;