How to check if a variable is an IEnumerable of some sort

C#GenericsForeachIenumerable

C# Problem Overview


basically I'm building a very generic T4 template and one of the things I need it to do is say print variable.ToString(). However, I want it to evaluate lists and foreach through them and instead print ListItem.ToString() My T4 template does not know what type variable will be ahead of time, that is why this is so generic.

But my current code that gets generated looks like this:

if(variable!=null)
  if(variable is IEnumerable) //error here
    foreach(var item in variable)
      Write(item.ToString());

I get a compiler error on the marked line for "Using the generic type System.Generic.Collections.IEnumerable requires one type argument"

I don't actually care what type it is though, I just want to know if you can foreach through the variable. What code should I use instead?

C# Solutions


Solution 1 - C#

You have already accepted an answer however,since generic IEnumerable<T> implements the non generic IEnumerable you can just cast to that.

// Does write handle null? Might need some sanity aswell.

var enumerable = variable as System.Collections.IEnumerable; 
                              
if (enumerable != null)
    foreach(var item in enumerable)
         Write(item);
else
    Write(item);     

Solution 2 - C#

If you want to test for the non-generic IEnumerable then you'll need to include a using System.Collections directive at the top of your source file.

If you want to test for an IEnumerable<T> of some kind then you'll need something like this instead:

if (variable != null)
{
    if (variable.GetType().GetInterfaces().Any(
            i => i.IsGenericType &&
            i.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
    {
        // foreach...
    }
}

Solution 3 - C#

The other answers have pointed out the generic/non-generic IEnumerable difference but I should also point out that you will also want to test for String specifically because it implements IEnumerable but I doubt you'll want to treat it as a collection of characters.

Solution 4 - C#

Since C# 7.0 you can also achieve this so:

if (variable is IEnumerable enumVar)
{
    foreach (var e in enumVar)
    {
        ...
    }
}

Solution 5 - C#

Well, somewhat simple but... if you only have:

using System.Collections.Generic;

you might need to add:

using System.Collections;

The former defines IEnumerable<T> and latter defines IEnumerable.

Solution 6 - C#

In general, with no non-generic base type/interface, this requires GetType and a recursive look-up through the base types/interfaces.

However, that doesn't apply here :-) Just use the non-generic IEnumerable (System.Collections.IEnumerable), from which the generic IEnumerable (System.Collections.Generic.IEnumerable<T>) inherits.

Solution 7 - C#

You can actually test the base class of any generic type directly.

instance.GetGenericTypeDefinition()  == typeof(IEnumerable<>)

Solution 8 - C#

If you don't care about object type and you are not in Generic method in C# 7.0+

        if (item is IEnumerable<object> enumVar)
        {
            foreach (var e in enumVar)
            {
                    e.ToString();

            }
        }

In C# < 7.0

        if (item is IEnumerable<object>)
        {
            var enumVar = item as IEnumerable<object>;
            foreach (var e in enumVar)
            {
                e.ToString();

            }
            //or you can cast an array to set values, 
            //since IEnumerable won't let you, unless you cast to IList :) 
            //but array version here 
            //https://stackoverflow.com/a/9783253/1818723
        }

Solution 9 - C#

This is an old question, but I wanted to show an alternative method for determining if a SomeType is IEnumerable:

var isEnumerable = (typeof(SomeType).Name == "IEnumerable`1");

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEarlzView Question on Stackoverflow
Solution 1 - C#user164771View Answer on Stackoverflow
Solution 2 - C#LukeHView Answer on Stackoverflow
Solution 3 - C#JoshView Answer on Stackoverflow
Solution 4 - C#TobiView Answer on Stackoverflow
Solution 5 - C#Schultz9999View Answer on Stackoverflow
Solution 6 - C#user166390View Answer on Stackoverflow
Solution 7 - C#Rob DearyView Answer on Stackoverflow
Solution 8 - C#Pawel CiochView Answer on Stackoverflow
Solution 9 - C#user152949View Answer on Stackoverflow