Y at-il un moyen de récupérer le type T
de IEnumerable<T>
par réflexion?obtenir le type T de IEnumerable <T>
par exemple.
J'ai une variable IEnumerable<Child>
info; je veux récupérer le type d'enfant par la réflexion
Y at-il un moyen de récupérer le type T
de IEnumerable<T>
par réflexion?obtenir le type T de IEnumerable <T>
par exemple.
J'ai une variable IEnumerable<Child>
info; je veux récupérer le type d'enfant par la réflexion
IEnumerable<T> myEnumerable;
Type type = myEnumerable.GetType().GetGenericArguments()[0];
Thusly,
IEnumerable<string> strings = new List<string>();
Console.WriteLine(strings.GetType().GetGenericArguments()[0]);
impressions System.String
.
Voir MSDN pour Type.GetGenericArguments
.
Edit: Je crois que ce répondra aux préoccupations dans les commentaires:
// returns an enumeration of T where o : IEnumerable<T>
public IEnumerable<Type> GetGenericIEnumerables(object o) {
return o.GetType()
.GetInterfaces()
.Where(t => t.IsGenericType
&& t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.Select(t => t.GetGenericArguments()[0]);
}
Certains objets implémentent plus d'un IEnumerable
générique il est donc nécessaire de retourner une énumération d'entre eux.
Edit: Bien que, je dois dire, c'est une idée terrible pour une classe pour mettre en œuvre IEnumerable<T>
pour plus d'un T
.
Cela ne fonctionnera pas: Essayez-le avec myEnumerable = new string [0]. –
Ou pire encore, écrivez une méthode avec des retours de rendement et essayez d'appeler GetType sur une variable créée avec cette méthode. Il vous dira que ce n'est pas un événement de type générique. Donc, fondamentalement, il n'y a pas de façon universelle d'obtenir T une variable d'instance de type IEnumerable
Ou essayez avec la classe MyClass: IEnumerable
typeof(IEnumerable<Foo>)
. GetGenericArguments()
[0]
renverra le premier argument générique - dans ce cas typeof(Foo)
.
Il suffit d'utiliser typeof(T)
EDIT: Ou utilisez .GetType() GetGenericParameter() sur un objet instancié si vous n'avez pas T.
Si vous connaissez le IEnumerable<T>
(via les génériques.), alors juste typeof(T)
devrait fonctionner. Dans le cas contraire (pour object
, ou IEnumerable
non générique), vérifier les interfaces mises en œuvre:
object obj = new string[] { "abc", "def" };
Type type = null;
foreach (Type iType in obj.GetType().GetInterfaces())
{
if (iType.IsGenericType && iType.GetGenericTypeDefinition()
== typeof(IEnumerable<>))
{
type = iType.GetGenericArguments()[0];
break;
}
}
if (type != null) Console.WriteLine(type);
Certains objets implémentent plus d'un IEnumerable générique. – jason
@Jason - et dans ces cas, la question de "trouver le T" est déjà une question douteuse; Je ne peux rien faire à ce sujet ... –
Un petit mot pour ceux qui essaient d'utiliser ceci avec un paramètre 'Type type' plutôt qu'un paramètre' object obj': vous ne pouvez pas simplement remplacer 'obj.GetType()' avec 'type' car si vous passez dans' typeof (IEnumerable
Merci beaucoup pour la discussion. Je l'ai utilisé comme base pour la solution ci-dessous, qui fonctionne bien pour tous les cas qui m'intéressent (IEnumerable, classes dérivées, etc). Je pense que je devrais partager ici au cas où quelqu'un en aurait besoin aussi:
Type GetItemType(object someCollection)
{
var type = someCollection.GetType();
var ienum = type.GetInterface(typeof(IEnumerable<>).Name);
return ienum != null
? ienum.GetGenericArguments()[0]
: null;
}
Je voudrais juste faire une méthode d'extension. Cela a fonctionné avec tout ce que je l'ai jeté.
public static Type GetItemType<T>(this IEnumerable<T> enumerable)
{
return typeof(T);
}
Cela ne fonctionnera pas si votre référence de temps de compilation est juste de type objet. –
Une alternative pour les situations simples où il est soit va être un IEnumerable<T>
ou T
- notez l'usage 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;
}
J'ai eu un problème similaire. La réponse sélectionnée fonctionne pour les instances réelles. Dans mon cas, j'avais seulement un type (à partir d'un PropertyInfo
).
La réponse sélectionnée échoue lorsque le type lui-même est typeof(IEnumerable<T>)
et non une implémentation de IEnumerable<T>
.
Pour ce cas, les travaux suivants:
public static Type GetAnyElementType(Type type)
{
// Type is Array
// short-circuit if you expect lots of arrays
if (type.IsArray)
return type.GetElementType();
// type is IEnumerable<T>;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof (IEnumerable<>))
return type.GetGenericArguments()[0];
// type implements/extends IEnumerable<T>;
var enumType = type.GetInterfaces()
.Where(t => t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.Select(t => t.GenericTypeArguments[0]).FirstOrDefault();
return enumType ?? type;
}
droit de vote prendre en compte jusqu'à la réponse choisie et question si vous trouvez ce code utile.
Ceci est une amélioration par rapport à la solution d'Eli Algranti en ce sens que cela fonctionnera également là où le type IEnumerable<>
est à n'importe quel niveau dans l'arbre d'héritage. Cette solution obtiendra le type d'élément à partir de Type
. Si le type n'est pas un IEnumerable<>
, il renvoie le type transmis. Pour les objets, utilisez GetType
. Pour les types, utilisez typeof
, puis appelez 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;
}
}
Dans quel contexte? Qu'est-ce que c'est IEnumerable? Est-ce une instance d'objet envoyée en argument? Ou quoi? –