11

I'm trying to detect if a particular instance of a Type object is a generic "IEnumerable"...

The best I can come up with is:

// theType might be typeof(IEnumerable<string>) for example... or it might not
bool isGenericEnumerable = theType.GetGenericTypeDefinition() == typeof(IEnumerable<object>).GetGenericTypeDefinition()
if(isGenericEnumerable)
{
    Type enumType = theType.GetGenericArguments()[0];
    etc. ...// enumType is now typeof(string) 

But this seems a bit indirect - is there a more direct/elegant way to do this?

Paul Hollingsworth
  • 13,124
  • 12
  • 51
  • 68
  • please see my follow up: http://stackoverflow.com/questions/1650310/net-reflection-determining-whether-an-array-of-t-would-be-convertible-to-some-o – Paul Hollingsworth Oct 30 '09 at 14:57

3 Answers3

22

You can use

if(theType.IsGenericType && theType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
    Type underlyingType = theType.GetGenericArguments()[0];
    //do something here
}

EDIT: added the IsGenericType check, thanks for the useful comments

Kenan E. K.
  • 13,955
  • 3
  • 43
  • 48
  • 2
    if theType is not generic, it will throw an `InvalidOperationException` - not a very good solution for a check IMHO. – Lucero Oct 30 '09 at 14:02
  • 3
    This only works if 'theType' is exactly typeof(IEnumerable<>), not if the type implements the interface. Hopefully that's what you're after. – Paul Turner Oct 30 '09 at 14:05
  • The "type" is actually an input parameter type - so I really do want to know if is exactly IEnumerable and not just convertable to IEnumerable... actually, I'm going to ask another question as this one is effectively answered. – Paul Hollingsworth Oct 30 '09 at 14:07
4

You can use this piece of code to determine if a particular type implements the IEnumerable<T> interface.

Type type = typeof(ICollection<string>);

bool isEnumerable = type.GetInterfaces()       // Get all interfaces.
    .Where(i => i.IsGenericType)               // Filter to only generic.
    .Select(i => i.GetGenericTypeDefinition()) // Get their generic def.
    .Where(i => i == typeof(IEnumerable<>))    // Get those which match.
    .Count() > 0;

It will work for any interface, however it will not work if the type you pass in is IEnumerable<T>.

You should be able to modify it to check the type arguments passed to each interface.

Paul Turner
  • 38,949
  • 15
  • 102
  • 166
2

Note that you cannot call GetGenericTypeDefinition() on a non-generic type, therefore, first check with IsGenericType.

I'm not sure if you want to check whether a type implements a generic IEnumerable<> or if you want to see if an interface type is IEnumerable<>. For the first case, use the following code (the inner check with interfaceType is the second case):

if (typeof(IEnumerable).IsAssignableFrom(type)) {
    foreach (Type interfaceType in type.GetInterfaces()) {
        if (interfaceType.IsGenericType && (interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))) {
            Console.WriteLine("{0} implements {1} enumerator", type.FullName, interfaceType.FullName); // is a match
        }
    }
}
Lucero
  • 59,176
  • 9
  • 122
  • 152
  • is this code referring to the legacy (non-generic) IEnumerable interface? – Paul Hollingsworth Oct 30 '09 at 13:57
  • Yes, because the generic one implies the non-generic one, it's a quick check to make sure that it is worth going over the interfaces at all. If `IEnumerable` (non-generic) is not implemented, `IEnumerable<>` (generic) cannot be either. – Lucero Oct 30 '09 at 13:59