The previously accepted answer est agréable mais il est faux. Heureusement, l'erreur est petite. La vérification de IEnumerable
n'est pas suffisante si vous voulez vraiment connaître la version générique de l'interface; il y a beaucoup de classes qui implémentent seulement l'interface non générique. Je vais donner la réponse dans une minute. Mais d'abord, je voudrais souligner que la réponse acceptée est trop compliquée, car le code suivant atteindre le même dans les circonstances données:
if (items[key] is IEnumerable)
Cela fait encore plus parce que cela fonctionne pour chaque élément séparément (et non sur leur sous-classe commune, V
).
Maintenant, pour la bonne solution. Ceci est un peu plus compliqué parce que nous devons prendre le type générique IEnumerable`1
(qui est, le type IEnumerable<>
avec un paramètre de type) et injecter le droit l'argument générique:
static bool IsGenericEnumerable(Type t) {
var genArgs = t.GetGenericArguments();
if (genArgs.Length == 1 &&
typeof(IEnumerable<>).MakeGenericType(genArgs).IsAssignableFrom(t))
return true;
else
return t.BaseType != null && IsGenericEnumerable(t.BaseType);
}
Vous pouvez tester l'exactitude de ce code facilement :
var xs = new List<string>();
var ys = new System.Collections.ArrayList();
Console.WriteLine(IsGenericEnumerable(xs.GetType()));
Console.WriteLine(IsGenericEnumerable(ys.GetType()));
rendements:
True
False
ne soyez pas trop préoccupé par le fait que celui-ci utilise la réflexion. Bien qu'il soit vrai que cela ajoute un temps d'exécution, l'utilisation de l'opérateur is
l'est également.
Bien sûr, le code ci-dessus est terriblement contraint et pourrait être étendu à une méthode plus généralement applicable, IsAssignableToGenericType
. La mise en œuvre suivante est légèrement incorrecte et je vais le laisser ici à des fins historiques seulement. Ne l'utilisez pas.Au lieu de cela, James has provided an excellent, correct implementation in his answer.
public static bool IsAssignableToGenericType(Type givenType, Type genericType) {
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
if (it.IsGenericType)
if (it.GetGenericTypeDefinition() == genericType) return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return baseType.IsGenericType &&
baseType.GetGenericTypeDefinition() == genericType ||
IsAssignableToGenericType(baseType, genericType);
}
Il échoue lorsque le genericType
est le même que givenType
; pour la même raison, il échoue pour les types nullable, à savoir
IsAssignableToGenericType(typeof(List<int>), typeof(List<>)) == false
IsAssignableToGenericType(typeof(int?), typeof(Nullable<>)) == false
J'ai créé un gist with a comprehensive suite of test cases.
C'est exactement ce que je cherchais. Merci! Il utilise toujours la réflexion, mais je cherchais la syntaxe "typeof (IEnumerable <>)". Merci! –
N'existe-t-il pas une autre façon de faire le contrôle sur le type, autre que d'utiliser "est"? –
la ligne finale devrait lire 'return (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == genericType) || IsAssignableToGenericType (baseType, genericType); 'Vous ne pouvez pas éviter la récursivité juste parce que la classe de base est générique. –