Octopoid
Octopoid

Reputation: 3698

Checking if Type or instance implements IEnumerable regardless of Type T

I'm doing a heavy bit of reflection in my current project, and I'm trying to provide a few helper methods just to keep everything tidy.

I'd like to provide a pair of methods to determine if a type or instance implements IEnumerable – regardless of the type T. Here is what I have at the moment:

public static bool IsEnumerable(this Type type)
{
    return (type is IEnumerable);
}

public static bool IsEnumerable(this object obj)
{
    return (obj as IEnumerable != null);
}

When I test them using

Debug.WriteLine("Type IEnumerable:   " + typeof(IEnumerable).IsEnumerable());
Debug.WriteLine("Type IEnumerable<>: " + typeof(IEnumerable<string>).IsEnumerable());
Debug.WriteLine("Type List:          " + typeof(List<string>).IsEnumerable());
Debug.WriteLine("Type string:        " + typeof(string).IsEnumerable());
Debug.WriteLine("Type DateTime:      " + typeof(DateTime).IsEnumerable());
Debug.WriteLine("Instance List:      " + new List<string>().IsEnumerable());
Debug.WriteLine("Instance string:    " + "".IsEnumerable());
Debug.WriteLine("Instance DateTime:  " + new DateTime().IsEnumerable());

I get this as the result:

Type IEnumerable:   False
Type IEnumerable<>: False
Type List:          False
Type string:        False
Type DateTime:      False
Instance List:      True
Instance string:    True
Instance DateTime:  False

The type method doesn't appear to work at all – I had expected a true for the direct System.Collections.IEnumerable match at least.

I'm aware that string is technically enumerable, albeit with a few caveats. Ideally in this case, however, I'd need the helper method to return false for it. I just need the instances with a defined IEnumerable<T> type to return true.

I've probably just missed something fairly obvious – can anyone point me in the right direction?

Upvotes: 61

Views: 52548

Answers (3)

Wouter
Wouter

Reputation: 2958

To check if some type implements IEnumerable regardless of T one needs to check the GenericTypeDefinition.

public static bool IsIEnumerableOfT(this Type type)
{
    return type.GetInterfaces()
               .Append(type) // ensure this type is also checked
               .Any(x => x.IsGenericType
                      && x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
}

Upvotes: 24

Wai Ha Lee
Wai Ha Lee

Reputation: 8816

In addition to Type.IsAssignableFrom(Type), you can also use Type.GetInterfaces():

public static bool ImplementsInterface(this Type type, Type interfaceType)
{
    // Deal with the edge case
    if ( type == interfaceType)
        return true;

    bool implemented = type.GetInterfaces().Contains(interfaceType);
    return implemented;
}

That way, if you wanted to check multiple interfaces you could easily modify ImplementsInterface to take multiple interfaces.

Upvotes: 17

dav_i
dav_i

Reputation: 28157

The following line

return (type is IEnumerable);

is asking "if an instance of Type, type is IEnumerable", which clearly it is not.

You want to do is:

return typeof(IEnumerable).IsAssignableFrom(type);

Upvotes: 96

Related Questions