116 votes

obtention du type T à partir de IEnumerable<T>

Existe-t-il un moyen de récupérer le type T de IEnumerable<T> par la réflexion ?

par exemple

j'ai une variable IEnumerable<Child> info ; Je veux récupérer le type de l'enfant par réflexion.

1 votes

Dans quel contexte ? Qu'est-ce que cet IEnumerable<T> ? Est-ce une instance d'objet envoyée comme argument ? Ou quoi ?

3voto

Tyler Huskins Points 11
public static Type GetInnerGenericType(this Type type)
{
  // Attempt to get the inner generic type
  Type innerType = type.GetGenericArguments().FirstOrDefault();

  // Recursively call this function until no inner type is found
  return innerType is null ? type : innerType.GetInnerGenericType();
}

Il s'agit d'une fonction récursive qui parcourt en premier la liste des types génériques jusqu'à ce qu'elle obtienne une définition de type concrète sans types génériques internes.

J'ai testé cette méthode avec ce type : ICollection<IEnumerable<ICollection<ICollection<IEnumerable<IList<ICollection<IEnumerable<T>>>>>>>>

qui devrait retourner T

2voto

rein Points 15639

Il suffit d'utiliser typeof(T)

EDIT : Ou utilisez .GetType().GetGenericParameter() sur un objet instancié si vous n'avez pas T.

2voto

Rob Church Points 1300

Une alternative pour les situations plus simples où il s'agit soit d'une IEnumerable<T> o T - noter l'utilisation de GenericTypeArguments au lieu de GetGenericArguments() .

Type inputType = o.GetType();
Type genericType;
if ((inputType.Name.StartsWith("IEnumerable"))
    && ((genericType = inputType.GenericTypeArguments.FirstOrDefault()) != null)) {

    return genericType;
} else {
    return inputType;
}

2voto

dahall Points 19

Je sais que c'est un peu vieux, mais je pense que cette méthode couvrira tous les problèmes et défis énoncés dans les commentaires. Crédit à Eli Algranti pour avoir inspiré mon travail.

/// <summary>Finds the type of the element of a type. Returns null if this type does not enumerate.</summary>
/// <param name="type">The type to check.</param>
/// <returns>The element type, if found; otherwise, <see langword="null"/>.</returns>
public static Type FindElementType(this Type type)
{
   if (type.IsArray)
      return type.GetElementType();

   // type is IEnumerable<T>;
   if (ImplIEnumT(type))
      return type.GetGenericArguments().First();

   // type implements/extends IEnumerable<T>;
   var enumType = type.GetInterfaces().Where(ImplIEnumT).Select(t => t.GetGenericArguments().First()).FirstOrDefault();
   if (enumType != null)
      return enumType;

   // type is IEnumerable
   if (IsIEnum(type) || type.GetInterfaces().Any(IsIEnum))
      return typeof(object);

   return null;

   bool IsIEnum(Type t) => t == typeof(System.Collections.IEnumerable);
   bool ImplIEnumT(Type t) => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}

1voto

Neo Points 685

Il s'agit d'une amélioration par rapport à la solution d'Eli Algranti, dans la mesure où elle fonctionnera également lorsque l'adresse de l'utilisateur est la suivante IEnumerable<> se trouve à n'importe quel niveau de l'arbre d'héritage.

Cette solution permettra d'obtenir le type d'élément à partir de n'importe quel Type . Si le type n'est pas un IEnumerable<> il retournera le type passé. Pour les objets, utilisez GetType . Pour les types, utilisez typeof puis appeler cette méthode d'extension sur le résultat.

public static Type GetGenericElementType(this Type type)
{
    // Short-circuit for Array types
    if (typeof(Array).IsAssignableFrom(type))
    {
        return type.GetElementType();
    }

    while (true)
    {
        // Type is IEnumerable<T>
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        {
            return type.GetGenericArguments().First();
        }

        // Type implements/extends IEnumerable<T>
        Type elementType = (from subType in type.GetInterfaces()
            let retType = subType.GetGenericElementType()
            where retType != subType
            select retType).FirstOrDefault();

        if (elementType != null)
        {
            return elementType;
        }

        if (type.BaseType == null)
        {
            return type;
        }

        type = type.BaseType;
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X