Как определить, реализует ли тип IList <>?
Я хочу написать метод, который использует Reflection, чтобы указать, реализует ли данный тип IList<T>
. Например:
IsGenericList(typeof(int)) // should return false
IsGenericList(typeof(ArrayList)) // should return false
IsGenericList(typeof(IList<int>)) // should return true
IsGenericList(typeof(List<int>)) // should return true
IsGenericList(typeof(ObservableCollection<int>)) // should return true
В моем использовании я могу предположить, что тип всегда будет созданным типичным типом (или вообще не общим).
К сожалению, это не так просто, как должно быть. Очевидное решение:
public bool IsGenericList(Type type)
{
return typeof(IList<>).IsAssignableFrom(type);
}
не работает; он всегда возвращает false. По-видимому, не создаваемые экземпляром типичные типы, такие как IList<>
, не реализуют IsAssignable. Я ожидал, что они будут такими: IList<>
не может быть назначен из List<T>
.
Я также пробовал это:
public bool IsGenericList(Type type)
{
if (!type.IsGenericType)
return false;
var genericTypeDefinition = type.GetGenericTypeDefinition();
return typeof(List<>).IsAssignableFrom(genericTypeDefinition);
}
I.e., превратите type
в его неинтерминированный родословный, например IList<int>
→ IList<>
, а затем снова попробуйте IsAssignableFrom. Это вернет true, если тип - это экземпляр IList<T>
, такой как IList<int>
, IList<object>
и т.д. Но он возвращает false для классов, реализующих IList<T>
, таких как List<int>
, ObservableCollection<double>
и т.д., Поэтому, по-видимому, IList<>
не присваивается из List<>
. Опять же, не то, что я ожидаю.
Как мне начать писать IsGenericList и заставить его работать так же, как в приведенных выше примерах?
Ответы
Ответ 1
Фактически, у вас не может быть экземпляра определения общего типа. Поэтому метод IsAssignableFrom() работает так, как ожидалось. Чтобы достичь желаемого, сделайте следующее:
public bool IsGenericList(Type type)
{
if (type == null) {
throw new ArgumentNullException("type");
}
foreach (Type @interface in type.GetInterfaces()) {
if (@interface.IsGenericType) {
if (@interface.GetGenericTypeDefinition() == typeof(ICollection<>)) {
// if needed, you can also return the type used as generic argument
return true;
}
}
}
return false;
}
Просто из любопытства, для чего вам это нужно?
Ответ 2
Я тоже хочу проверить, реализует ли тип IList<T>
для некоторого T. Я сделал очевидное изменение ответа Lucero, но это вызвало тонкая ошибка, нет в исходном ответе. Здесь мое окончательное редактирование:
/// <summary>
/// Test if a type derives from IList of T, for any T.
/// </summary>
public bool TestIfGenericList(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
var interfaceTest = new Predicate<Type>(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>));
return interfaceTest(type) || type.GetInterfaces().Any(i => interfaceTest(i));
}
Ответ 3
Используя это:
http://msdn.microsoft.com/en-us/library/system.type.findinterfaces.aspx
Я пробовал это:
public class Test : IList<string>
{
//implementation left out...
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
TypeFilter myFilter = new TypeFilter(MyInterfaceFilter);
Type type = t.GetType();
Type[] x = type.FindInterfaces(myFilter, "System.Collections.Generic.IList");
Console.WriteLine(x.Length);
}
public static bool MyInterfaceFilter(Type typeObj, Object criteriaObj)
{
if (typeObj.ToString().Contains(criteriaObj.ToString()))
return true;
else
return false;
}
}
Ответ 4
У Лусеро/Рида Копси есть правильное решение. Чтобы сделать его более кратким, вот он в LINKified форме:
var isGenericList = type.GetInterfaces().Any(t => t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof(IList<>));
Ответ 5
Это проходит ваши тесты...
public static bool IsGenericList( Type type )
{
return type.Name == "IList`1" || type.GetInterface( "IList`1" ) != null;
}
Ответ 6
Вы пробовали вызывать Type.GetInterface()? Это не совсем понятно из справки, но я думаю, что он будет искать интерфейсы, реализуемые базовыми типами, в дополнение к самому типу. Если нет, вы всегда можете пройти через Type.BaseType
и снова вызвать GetInterface()
.
Ответ 7
Используйте оператор :
Оператор is используется для проверки является ли тип времени выполнения объекта совместим с данным типом.