Как я могу сказать, реализует ли тип IList <>? - PullRequest
16 голосов
/ 04 июня 2009

Я хочу написать метод, который использует 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<>, не реализуют IsAssignableF, как я ожидал от них: IList<> нельзя назначить из List<T>.

Я тоже пробовал это:

public bool IsGenericList(Type type)
{
    if (!type.IsGenericType)
        return false;
    var genericTypeDefinition = type.GetGenericTypeDefinition();
    return typeof(List<>).IsAssignableFrom(genericTypeDefinition);
}

Т.е., превратить type в его неинстанцированный обобщенный тип, например IList<int> -> IList<>, а затем снова попробовать IsAssignableFrom. Это вернет true, когда type является экземпляром IList<T>, таким как IList<int>, IList<object> и т. Д. Но он возвращает false для классов, которые реализуют IList<T>, таких как List<int>, ObservableCollection<double> и т. Д., Так что очевидно IList<> нельзя назначить с List<>. Опять же, не то, что я ожидал.

Как мне написать ISGenericList и заставить его работать, как в приведенных выше примерах?

Ответы [ 8 ]

26 голосов
/ 04 июня 2009

На самом деле вы не можете иметь экземпляр определения общего типа. Поэтому метод 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;
}

Просто из любопытства, зачем тебе это?

15 голосов
/ 27 ноября 2012

Я тоже хочу проверить, реализует ли тип 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));
    }
2 голосов
/ 04 июня 2009

Используя это: 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;
        }
    }
2 голосов
/ 04 июня 2009

Lucero / Reed Copsey оба имеют правильное решение сейчас. Просто чтобы сделать его более кратким, вот оно в LINQified форме:

var isGenericList = type.GetInterfaces().Any(t => t.IsGenericType && 
    t.GetGenericTypeDefinition() == typeof(IList<>));
1 голос
/ 04 июня 2009

Это проходит ваши тесты ...

public static bool IsGenericList( Type type )
{
  return type.Name == "IList`1" || type.GetInterface( "IList`1" ) != null;
}
0 голосов
/ 08 января 2019

Мне понравился Ответ полковника Паника , но я решил сделать ответ более общим, чтобы я мог использовать его в других сценариях:

    public static bool InstanceOfGenericType(this Type self, Type genericType)
    {
        return self.IsGenericType && self.GetGenericTypeDefinition() == genericType;
    }

    public static bool InstanceOfGenericInterface(this Type self, Type ifaceType)
    {
        return self.InstanceOfGenericType(ifaceType) 
            || self.GetInterfaces().Any(i => i.InstanceOfGenericType(ifaceType));
    }

    public static bool IsIList(this Type t)
    {
        return t.InstanceOfGenericInterface(typeof(IList<>));
    }
0 голосов
/ 04 июня 2009

Вы пытались вызвать Type.GetInterface () ? Из справки не совсем понятно, но я думаю, что он будет искать интерфейсы, реализованные базовыми типами, в дополнение к самому типу. Если нет, вы всегда можете просмотреть Type.BaseType и снова вызвать GetInterface().

0 голосов
/ 04 июня 2009

Используйте оператор " is ":

Оператор is используется для проверки является ли тип времени выполнения объекта совместим с данным типом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...