Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GetGenericTypeDefinition returning false when looking for IEnumerable<T> in List<T>

Following this question, why does enumerable in this:

Type type = typeof(List<string>);
bool enumerable = (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>));

return false?


Edit 1

As the above doesn't work, what would be the best way to determine if a class implements IEnumerable?

like image 882
Ryall Avatar asked Dec 15 '09 17:12

Ryall


4 Answers

Here, I might use GetListType(type) and check for null:

static Type GetListType(Type type) {
    foreach (Type intType in type.GetInterfaces()) {
        if (intType.IsGenericType
            && intType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) {
            return intType.GetGenericArguments()[0];
        }
    }
    return null;
}
like image 193
Marc Gravell Avatar answered Nov 20 '22 00:11

Marc Gravell


Because

(typeof(List<String>)).GetGenericTypeDefinition()

is returning

typeof(List<>)

GetGenericTypeDefinition can only return one type, not all the unbound types implemented by the target instance of Type.

To determine if X<T> implements IY<T> either

  • Reify T (i.e. make it a real type), and check with concrete types. I.e. does X<string> implement IY<string>. This can be done via reflection or with the as operator.

  • Type.GetInterafces() (or Type.GetInterface(t)).

The second is going to be easier. Especially as this also gives false:

Type t = typeof(List<string>).GetGenericTypeDefinition();
bool isAssign = typeof(IEnumerable<>).IsAssignableFrom(t);
like image 25
Richard Avatar answered Nov 20 '22 00:11

Richard


If you want a quick test for specific closed generic types - for example, to check if List<string> implements IEnumerable<string> - then you can do something like this:

Type test = typeof(List<string>);
bool isEnumerable = typeof(IEnumerable<string>).IsAssignableFrom(test);

If you want a more general-purpose solution that works for any IEnumerable<T> then you'll need to use something like this instead:

Type test = typeof(List<string>);
bool isEnumerable = test.GetInterfaces().Any(i =>
    i.IsGenericType && (i.GetGenericTypeDefinition() == typeof(IEnumerable<>)));
like image 2
LukeH Avatar answered Nov 20 '22 00:11

LukeH


The following returns true and is kind of to the point, checking the interfaces:

 enumerable = typeof(List<string>).GetInterfaces()
               .Contains(typeof(IEnumerable<string>));
like image 1
Henk Holterman Avatar answered Nov 19 '22 23:11

Henk Holterman