Как определить, реализует ли тип 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 используется для проверки является ли тип времени выполнения объекта совместим с данным типом.