7

I'd like to do something like this

void DoSomething<T>(T param)
{
    if param is IEnumerable<?>
    {
        loop param and do stuff
    }
}

I don't know what to do in the place of the question mark. And is it possible at all?

horgh
  • 17,918
  • 22
  • 68
  • 123
tranmq
  • 15,168
  • 3
  • 31
  • 27
  • If `param` is not of type `IEnumerable`, do you want to do anything? If not, why not restrict `T` to be of type `IEnumerable` with [where](http://msdn.microsoft.com/en-us/library/bb384067.aspx)? – Adam Mihalcin Sep 29 '12 at 02:21
  • Possible answers here: http://stackoverflow.com/questions/1846671/determine-if-collection-is-of-type-ienumerablet – Ian Andrew Irwin Sep 29 '12 at 02:22
  • Answer in stack overflow post [click here][1] [1]: http://stackoverflow.com/questions/906499/getting-type-t-from-ienumerablet – Deval Ringwala Sep 29 '12 at 02:26
  • Also check my answer to recent question: http://stackoverflow.com/questions/12649349/how-to-pass-a-wildcard-in-c-sharp if you want to restrict type of T. – Alexei Levenkov Sep 29 '12 at 02:50
  • What will you do with the items in the loop? You aren't going to have strongly typed instances even if you do iterate through the loop with a non-generic `IEnumerable` implementation. – casperOne Sep 29 '12 at 13:49

3 Answers3

10

What you are looking for is :

if (T is IEnumerable) { .. }

but if you expect T to be IEnumerable all the time you can do:

void DoSomething<T>(T param) where T : IEnumerable
{
    foreach (var t in param) { ... }
}

or checking the type of the values inside the IEnumerable:

public void DoSomething<T,U>(T val) where T : IEnumerable<U>
{
    foreach (U a in val)
    {
    }
}

Without having to worry to check it yourself, the compiler will do it for you, which is one of the nice things of having a static type system and compiler :)

Francisco Soto
  • 10,277
  • 2
  • 37
  • 46
  • i think he's actually try to check that the IEnumerable of a specific type, not just a general IEnumerable. the link in the comment under the question handles that scenario – Mike Corcoran Sep 29 '12 at 02:24
  • Good point. Ill complete the answer with that scenario, thank you. – Francisco Soto Sep 29 '12 at 02:25
  • Thanks for the good reply. The problem is that I don't expect T to be IEnumerable all the time. In fact, I already have a method `void ProcessList(IEnumerable list)` and want to reuse it in `DoSomething()` if the argument is an IEnumerable. – tranmq Sep 29 '12 at 04:49
  • @mbqt it should be noted that all implementations of `IEnumerable` implement `IEnumerable` (it derives from it after all) but an implementation of `IEnumerable` is **not** guaranteed to implement `IEnumerable`, making that assumption would be incorrect. – casperOne Sep 29 '12 at 13:47
  • 3
    I realize this is an old post, but (T is IEnumerable) not only does not compile, it's not correct. (typeof(T) is IEnumerable) compiles, but is still false, since typeof(T) is ultimately an Object. The correct way to do this seems to be: typeof(IEnumerable).IsAssignableFrom(typeof(T)) – Trey Jun 28 '16 at 18:20
  • @Trey: Thanks for that correction. I just tried the code in this answer and was getting an error `'T' is a type, which is not valid in the given context`. Your code worked. – Simon Elms Sep 14 '22 at 06:06
0

There are a few ways:

void DoSomething<T>(T param)
{
    if (param is IEnumerable)
    {
        foreach (var item in (IEnumerable)param)
        {
            // Do something
        }
    }
}

void DoSomething<T>(T param)
{
    if (param is IEnumerable<string>)
    {
        foreach (var item in (IEnumerable<string>)param)
        {
            // Do something
        }
    }
}

void DoSomething<T,TItem>(T param)
{
    if (param is IEnumerable<TItem>)
    {
        foreach (var item in (IEnumerable<TItem>)param)
        {
            // Do something
        }
    }
}
decyclone
  • 30,394
  • 6
  • 63
  • 80
  • Best practice is to use `as` rather than `is`-plus-direct-cast, since `as` does the expensive run-time type check only once, while is-plus-direct-cast does it twice. – phoog Sep 29 '12 at 05:59
0

You have to check the open generic type of each interface that the class implements, like so:

bool implements = typeof(T).GetInterfaces().Where(t => t.IsGenericType && 
    t.GetGenericTypeDefinition() == typeof(IEnumerable<>)).Any();

This will allow you to determine whether or not a type implements IEnumerable<T> without actually knowing what the type T is. Remember that the type can implement IEnumerable<T> multiple times.

If you simply want the sequence of types that are type parameters for IEnumerable<T>, you can change the above query to;

IEnumerable<Type> types = typeof(T).GetInterfaces().
    Where(t => t.IsGenericType && 
        t.GetGenericTypeDefinition() == typeof(IEnumerable<>)).
    Select(t => t.GetGenericArguments()[0]);
casperOne
  • 73,706
  • 19
  • 184
  • 253