web-dev-qa-db-fra.com

C # - Obtenir le type d'élément pour une liste générique

Quel serait le meilleur moyen d'obtenir le type d'éléments qu'une liste générique contient? Il est assez facile de saisir le premier élément de la collection et d'appeler .GetType (), mais je ne peux pas toujours être sûr qu'il y aura un élément dans la collection.

J'espère que cela a du sens.

Merci,
Fiston

29
Sonny Boy

Vous pouvez utiliser la méthode Type.GetGenericArguments à cette fin.

List<Foo> myList = ...

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

Pour une approche plus robuste:

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];
}

Mais si votre variable est typée List<T>, vous pouvez simplement utiliser typeof(T). Par exemple:

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

Notez que vous n'avez même pas vraiment besoin du paramètre someList. Cette méthode est juste un exemple d'utilisation de typeof si vous êtes déjà dans une méthode générique. Vous ne devez utiliser l'approche de réflexion que si vous n'avez pas accès au jeton T (la liste est stockée dans une variable de type non générique, telle qu'une variable typée IList, object, etc.).

7
cdhowie
list.GetType().GetGenericArguments()[0]
5
Mehrdad

Voici une autre méthode qui fonctionne pour les collections non génériques:

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

Autrement dit, obtenez le type de retour foo[x], où foo est du type spécifié.

Exemples:

// 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)));

La méthode GetItemType ci-dessus présente quelques problèmes, cependant:

  • Il jette une NullReferenceException si le type n'a pas d'opérateur d'indexation.

  • Il génère une AmbiguousMatchException si le type comporte plusieurs surcharges pour l'opérateur d'indexation (par exemple, this[string] et this[int]).

Voici une version plus raffinée:

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];
}
4
Joey Adams

Qu'en est-il de cela, tout est statique (par exemple, aucune instance requise) et rapide (pas de boucle, pas d'utilisation de linq), et c'est simple :) ces travaux pour les collections:

    [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;
    }

Et quelques tests unitaires simples:

        [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());
        }

Notez le fait qu'il existe deux manières de regarder cela, un type peut être retourné par l'indexeur et un autre type par l'énumérateur. Le test unitaire montre les deux.

Amusez-vous, Frans.

P.s. Pour les biens énumérables:

    [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;
    }

Et pour enquêteur:

    [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;
    }
1
FdW
    public Type GetType(IEnumerable<object> resultList)
    {
        return resultList.GetType().GetElementType();
    }
0
joyce

Ancienne question nouvelle méthode avec dynamic

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

private static Type GetTypeT<T>(IEnumerable<T> data)
{
    return typeof(T);
}
0
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
0
toddmo