The previously accepted answer ist schön, aber es ist falsch. Zum Glück ist der Fehler ein kleiner. Die Überprüfung auf IEnumerable
ist nicht genug, wenn Sie wirklich über die generische Version der Schnittstelle informiert werden möchten; Es gibt viele Klassen, die nur die nicht generische Schnittstelle implementieren. Ich werde die Antwort in einer Minute geben. Zunächst aber möchte ich darauf hinweisen, dass die akzeptierte Antwort zu kompliziert ist, da der folgende Code das gleiche unter den gegebenen Umständen erreichen würde:
if (items[key] is IEnumerable)
Dies gilt noch mehr, weil sie separat für jedes Element funktioniert (und nicht auf ihre gemeinsame Unterklasse, V
).
Jetzt für die richtige Lösung. Dies ist ein wenig komplizierter, weil wir den generischen Typ IEnumerable`1
nehmen (das heißt, der Typ IEnumerable<>
mit einem Typ-Parameter) und injizieren das Recht allgemeine Argument:
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);
}
Sie die Richtigkeit dieser Code testen können leicht :
var xs = new List<string>();
var ys = new System.Collections.ArrayList();
Console.WriteLine(IsGenericEnumerable(xs.GetType()));
Console.WriteLine(IsGenericEnumerable(ys.GetType()));
ergibt:
True
False
übermäßig besorgt über die Tatsache werden Sie nicht, dass diese Reflexion verwendet. Es ist zwar wahr, dass dies einen Laufzeit-Overhead hinzufügt, aber auch die Verwendung des Operators is
.
Natürlich ist der obige Code furchtbar eingeschränkt und könnte in eine allgemein anwendbare Methode, IsAssignableToGenericType
erweitert werden. Die folgende Implementierung ist etwas falsch und ich lasse es hier nur für historische Zwecke. Nicht verwenden.Stattdessen 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);
}
Es schlägt fehl, wenn die genericType
die gleiche wie givenType
ist; Aus dem gleichen Grund, versagt es für Nullable Types, das heißt
IsAssignableToGenericType(typeof(List<int>), typeof(List<>)) == false
IsAssignableToGenericType(typeof(int?), typeof(Nullable<>)) == false
ich eine gist with a comprehensive suite of test cases erstellt haben.
Genau das habe ich gesucht. Vielen Dank! Es verwendet immer noch die Reflexion, aber ich suchte nach der Syntax "typeof (IEnumerable <>)". Vielen Dank! –
Gibt es keine andere Möglichkeit, den Typ zu überprüfen, als "is" zu verwenden? –
Die letzte Zeile sollte 'return (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == genericType) || lesen IsAssignableToGenericType (baseType, genericType); 'Sie können die Rekursion nicht vermeiden, nur weil die Basisklasse generisch ist. –