The previously accepted answer is good, but it is wrong. Fortunately, the error is small. Checking for IEnumerable not enough if you really want to know about the general version of the interface; There are many classes that implement only the neon interface. I will give an answer in a minute. Firstly, I would like to note that the accepted answer is too complicated, as the following code will achieve the same in the given circumstances:
if (items[key] is IEnumerable)
This does even more, because it works for each element separately (and not for the general subclass of V ).
Now, for the right decision. This is a bit more complicated because we need to take the generic type IEnumerable`1 (i.e. type IEnumerable<> with one type parameter) and enter the correct generic 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); }
You can easily verify the correctness of this code:
var xs = new List<string>(); var ys = new System.Collections.ArrayList(); Console.WriteLine(IsGenericEnumerable(xs.GetType())); Console.WriteLine(IsGenericEnumerable(ys.GetType()));
gives:
True False
Do not worry too much about using reflection. Although it is true that this adds overhead at runtime, the is operator is also used.
Of course, the above code is terribly limited and can be extended to the more public IsAssignableToGenericType method. The following implementation is somewhat incorrect 1 and I left it here for historical purposes only. Do not use it . Instead, James 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); }
1 It fails when genericType matches givenType ; for the same reason, it fails for types with a null value, i.e.
IsAssignableToGenericType(typeof(List<int>), typeof(List<>)) == false IsAssignableToGenericType(typeof(int?), typeof(Nullable<>)) == false
Ive created a gist with a complete set of test cases .