Подтвердить что ты не робот

С# - Получить тип элемента для общего списка

Каким будет лучший способ получения типов элементов, которые содержит общий список? Это достаточно просто, чтобы захватить первый элемент в коллекции и вызвать .GetType(), но я не всегда могу быть уверен, что в коллекции будет элемент.

Надеюсь, что это имеет смысл.

Спасибо,
Сонни

4b9b3361

Ответ 1

Для этой цели вы можете использовать метод Type.GetGenericArguments.

List<Foo> myList = ...

Type myListElementType = myList.GetType().GetGenericArguments().Single();

Ответ 2

Для более надежного подхода:

public static Type GetListType(object someList)
{
    if (someList == null)
        throw new ArgumentNullException("someList");

    var type = someList.GetType();

    if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(List<>))
        throw new ArgumentException("someList", "Type must be List<>, but was " + type.FullName);

    return type.GetGenericArguments()[0];
}

Но если ваша переменная напечатана List<T>, вы можете просто использовать typeof(T). Например:

public static Type GetListType<T>(List<T> someList)
{
    return typeof(T);
}

Обратите внимание, что вам действительно не нужен параметр someList. Этот метод является просто примером использования typeof, если вы уже используете общий метод. Вам просто нужно использовать подход отражения, если у вас нет доступа к токену T (список хранится в переменной, не типизированной в типизированном виде, например, в типе IList, object и т.д.)..

Ответ 3

list.GetType().GetGenericArguments()[0]

Ответ 4

Здесь другой способ, который работает и для не общих коллекций:

static Type GetItemType(Type collectionType)
{
    return collectionType.GetMethod("get_Item").ReturnType;
}

То есть получить тип возврата foo[x], где foo имеет указанный тип.

Примеры:

// Generic type; prints System.Int32
Console.WriteLine(GetItemType(typeof(List<int>)));

// Non-generic type; prints System.String
Console.WriteLine(GetItemType(typeof(System.Collections.Specialized.StringCollection)));

В приведенном выше методе GetItemType есть несколько проблем:

  • Он выдает NullReferenceException, если тип не имеет оператора индексирования.

  • Он выдает AmbiguousMatchException, если тип имеет несколько перегрузок для оператора индексирования (например, this[string] и this[int]).

Вот более утонченная версия:

public static Type GetItemType(this Type collectionType)
{
    var types =
        (from method in collectionType.GetMethods()
         where method.Name == "get_Item"
         select method.ReturnType
        ).Distinct().ToArray();
    if (types.Length == 0)
        return null;
    if (types.Length != 1)
        throw new Exception(string.Format("{0} has multiple item types", collectionType.FullName));
    return types[0];
}

Ответ 5

Что бы это ни было, все его статические (например, не требуемые экземпляры) и быстрые (без циклов, без использования linq), и это просто:) они работают для коллекций:

    [System.Diagnostics.DebuggerHidden]
    public static Type GetIndexedType(this ICollection poICollection)
    {
        PropertyInfo oPropertyInfo = poICollection == null ? null : poICollection.GetType().GetProperty("Item");
        return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
    }

    [System.Diagnostics.DebuggerHidden]
    public static Type GetEnumeratedType(this ICollection poICollection)
    {
        PropertyInfo oPropertyInfo = poICollection == null ? null : poICollection.GetType().GetMethod("GetEnumerator").ReturnType.GetProperty("Current");
        return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
    }

И несколько простых модульных тестов:

        [Test]
        public void GetIndexedType()
        {
            Assert.AreEqual(null, ((ICollection)null).GetIndexedType());
            Assert.AreEqual(typeof(int), (new List<int>()).GetIndexedType());
            Assert.AreEqual(typeof(bool), (new SortedList<string, bool>()).GetIndexedType());
        }

        [Test]
        public void GetEnumeratedType()
        {
            Assert.AreEqual(null, ((ICollection)null).GetEnumeratedType());
            Assert.AreEqual(typeof(int), (new List<int>()).GetEnumeratedType());
            Assert.AreEqual(typeof(KeyValuePair<string, bool>), (new SortedList<string, bool>()).GetEnumeratedType());
        }

Обратите внимание на то, что есть два способа взглянуть на это, один тип может быть возвращен индексом, а другой тип может быть возвращен перечислителем. unit test do показывают оба.

Удачи, Frans.

P.s. Для перечислений:

    [System.Diagnostics.DebuggerHidden]
    public static Type GetEnumeratedType(this System.Collections.IEnumerable poIEnumerable)
    {
        PropertyInfo oPropertyInfo = poIEnumerable == null ? null : poIEnumerable.GetType().GetMethod("GetEnumerator").ReturnType.GetProperty("Current");
        return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
    }

И для счетчика:

    [System.Diagnostics.DebuggerHidden]
    public static Type GetEnumeratedType(this System.Collections.IEnumerator poIEnumerator)
    {
        PropertyInfo oPropertyInfo = poIEnumerator == null ? null : poIEnumerator.GetType().GetProperty("Current");
        return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
    }

Ответ 6

Public Shared Function ListItemType(ListType As System.Type) As System.Type

  If Not ListType.IsGenericType Then
    If ListType.BaseType IsNot Nothing AndAlso ListType.BaseType.IsGenericType Then
      Return ListItemType(ListType.BaseType)
    End If
  Else
    Return ListType.GetGenericArguments.Single
  End If
End Function

Ответ 7

Старый вопрос новый метод с dynamic

void Foo(){
   Type type GetTypeT(data as dynamic);
}

private static Type GetTypeT<T>(IEnumerable<T> data)
{
    return typeof(T);
}

Ответ 8

    public Type GetType(IEnumerable<object> resultList)
    {
        return resultList.GetType().GetElementType();
    }