Разве общий IList не может быть назначен из общего списка? - PullRequest
2 голосов
/ 24 июля 2009
bool IsTypeAGenericList(Type listType)
{
  typeof(IList<>).IsAssignableFrom(listType.GetGenericTypeDefinition())
}

возвращает ложь, если дано typeof(List<int>).

Я предполагаю, что это потому, что два типа параметров могут быть разными, правильно?

Ответы [ 4 ]

8 голосов
/ 24 июля 2009

На самом деле, это работает:

public static bool IsGenericList(Type type)
{
  if (!type.IsGenericType)
    return false;
  var genericArguments = type.GetGenericArguments();
  if (genericArguments.Length != 1)
    return false;

  var listType = typeof (IList<>).MakeGenericType(genericArguments);
  return listType.IsAssignableFrom(type);
}
3 голосов
/ 24 июля 2009

Это действительно имеет отношение к открытым построенным типам.

Когда вы говорите:

class List<T> : IList<T>

Вы на самом деле говорите: мой класс называется List, у него есть один параметр типа с именемT, и он реализует интерфейс, который построен из IList <> с использованием того же T . Таким образом, T в части определения и T в части «Implements» ссылаются на один и тот же параметр типа - вы объявляете его перед двоеточием, а затем сразу же ссылаетесь на него после двоеточия.

Это сбивает с толку, потому что параметр типа IList<> также называется T - но это совершенно другой параметр типа. Итак, давайте повторно объявим наш конкретный класс следующим образом:

class List<U> : IList<U>

Это полностью эквивалентно вышеприведенному, только теперь мы можем сказать «U», когда мы ссылаемся на параметр типа List, и T, когда мыобратитесь к одному из IList. Это разные типы.

Теперь становится проще понять, почему определение универсального типа List<U> (что вы имеете в виду, когда говорите typeof(List<>)) не реализует определение типа generifc IList<T> (это то, что вы имеете в виду, когда говорите typeof(IList<>)), но, скорее, он реализует открытый универсальный составной тип IList<U> (то есть IList, построенный с использованием собственного пареметра типа List).

Таким образом, в основном определения универсальных типов никогда не наследуют и не реализуют определения других универсальных типов - они обычно реализуют открытые составные типы, используя свои собственные параметры типа с другими определениями универсальных типов.

Ответ Ripper234 показывает, как обрабатывать этот конкретный случай с помощью Reflection, поэтому я не буду его повторять;Я просто хотел уточнить взаимосвязь между этими типами, и я надеюсь, что она получилась хотя бы несколько понятной.

2 голосов
/ 24 июля 2009

Я полагаю, что метод на самом деле не имеет смысла, потому что экземпляр никогда не имеет универсального типа - он всегда создается с аргументом определенного типа.

Другими словами, выникогда не может быть «открытой» переменной для присваивания или ссылки на открытый экземпляр для использования в качестве значения для присваивания.

Как вы говорите, вы не знаете, будут ли параметры типато же самое - так (например) вы могли бы определить:

class BizarreList<T> : IList<int>

Такое чувство, что должен быть какой-то способ выражения отношений, хотя ...

1 голос
/ 29 октября 2013

Вот метод расширения из AutoMapper:

    public static bool IsCollectionType(this Type type)
    {
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ICollection<>))
        {
            return true;
        }

        IEnumerable<Type> genericInterfaces = type.GetInterfaces().Where(t => t.IsGenericType);
        IEnumerable<Type> baseDefinitions = genericInterfaces.Select(t => t.GetGenericTypeDefinition());

        var isCollectionType = baseDefinitions.Any(t => t == typeof(ICollection<>));

        return isCollectionType;
    }
...