Checking if Type or instance implements IEnumerable regardless of Type T
Solution 1
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);
Solution 2
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.
Solution 3
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().Any(x => x.IsGenericType
&& x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
}
Related videos on Youtube
Octopoid
Updated on July 09, 2022Comments
-
Octopoid almost 2 years
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 typeT
. 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 directSystem.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 returnfalse
for it. I just need the instances with a definedIEnumerable<T>
type to returntrue
.I've probably just missed something fairly obvious – can anyone point me in the right direction?
-
Peter Duniho about 9 yearsI don't understand the question. It's clear why
typeof()
any type doesn't returntrue
; you are asking whether the type object implements the interface, not the type itself. Maybe you wantIsAssignableFrom()
? But in what way do you thinkstring
doesn't qualify? It does have "a definedIEnumerable<T>
type". -
Octopoid about 9 yearsYep, that was the issue with the type one - I've been looking at nests of reflection jumping between types and instances all day and got more than a little confused!
string
does qualify, however in this case I do really need to rule it out - it's probably more of a matter of method naming at this stage. I think I'll just leave this as it is and add another one that just type checks on string first. -
Jcl about 9 yearsAgree with @JeroenMostert ... the "duplicate" is asking if a type is implementing
IEnumerable<x>
using reflection, this one is asking if a type is implementingIEnumerable
, which is a different thing and requires a different solution (as proven by the different accepted answers) -
Andie2302 almost 4 yearsMaybe you look for
ICollection<x>
instead ofIEnumerable<x>
-
-
Jcl about 9 years@Octopoid a string implements
IEnumerable<char>
, so it's true, because that's what you are asking for -
dav_i about 9 years@Octopoid That's the correct behavior.
string
is anIEnumerable<char>
, which is anIEnumerable
. -
Octopoid about 9 yearsYeah,
string
does qualify, however in this case I do really need to rule it out - it's probably more of a matter of method naming at this stage. I think I'll just leave this as it is and add another one that just type checks on string first. -
dav_i about 9 years@Octopoid Yeah, just check if it's string first.
-
dav_i about 9 years@Octopoid Actually it'll be more performant if you check it second!
-
Octopoid about 9 years@dav_i Good point! Very strange, not sure why, it just feels like it would be the other way until you stop and think.. at any rate - checks switched! :)
-
dav_i about 9 years@Octopoid I had the same "oh, wait a sec" moment. Hence the double comment :)
-
Jcl about 9 yearsIf you are ruling out
string
for some reason, without seeing your code or knowing the requirements, you probably want to rule out many possible others too (specially if you are making a library that can be used in future code by types unknown at this point). I fail to see whystring
would be different to many other possibleIEnumerable
s. If that's the case, you'd be better off being explicit about what you support, instead of using "implementingIEnumerable
" as a check -
Wouter over 3 yearsI don't now why this is the accepted answe. IEnumerable is not the same as IEnumerable<T> regardless of T. There can be types that only implement IEnumerable.
-
Jason C almost 3 yearsSmall correction: This fails in the edge case where
type
is itselftypeof(IEnumerable<T>)
, which can give silent failures in certain situations: dotnetfiddle.net/vLFdHW -- the fix is easy though, just throw a.Append(type)
right before that.Any
so that the type itself is also checked: dotnetfiddle.net/5wj1KE -
Jason C almost 3 years@Wouter It's because checking
IEnumerable
generally accomplishes most goals in practice. Another thing all the answers here miss is that if the ultimate goal is to see if a type is compatible withforeach
, checking forIEnumerable
isn't the way to go, since that's not actually whatforeach
requires: if that's the goal the correct way is to forget about interfaces and explicitly check for thepublic X GetEnumerator()
method, and check that method's return type for apublic bool MoveNext()
method and apublic Y Current
property. Then use those to iterate. -
Wouter almost 3 years@JasonC not for my scenario :). Good to know about foreach only needs a method not the interface. Do you know of any examples where this is actually the case?
-
Jason C almost 3 years@Wouter You can find them with pastebin.com/S5MkzmXK (I stuck a list of what I found there too, there's not many). Also there's
Span<T>
except it's a ref struct so you'd never encounter it generically. There's probably some other standard ref structs too that aren't easily findable. See also. -
Wouter almost 2 yearsbut... Why use IsIEnumerableOfT if you already know compile time that it is true?
-
Jason C almost 2 yearsYou'd use it if you didn't know at compile time that it was true, e.g. an instance of some arbitrary
Type
.