Noah
Noah

Reputation: 15340

In C# is it possible to determine if a variable has an enumerator

I am trying to write a generic comparison routine. However, some of the items in my class are in Collections and I need to enumerate to compare.

Is there an easy way, without a try/catch block to determine is a variable supports GetEnumerator()

Upvotes: 0

Views: 243

Answers (6)

Anthony Pegram
Anthony Pegram

Reputation: 126992

The answers suggesting you check to see if the object is an IEnumerable are reasonably spot on. It's going to be the case the overwhelming majority of the time that your collection or object will implement that interface if it supports enumeration. But it is not required.

For something to be enumerated in a foreach, it really only needs to expose a GetEnumerator() method that returns an object with suitable MoveNext() and Current implementations. Consider something like:

class CustomCollection
{
    public CustomEnumerator GetEnumerator()
    {
        return new CustomEnumerator();
    }
}

class CustomEnumerator
{
    public bool MoveNext()
    {
        return (++this.Current <= 10);
    }

    public int Current { get; private set; }
}

You can put new CustomCollection() into a loop and get the values 1..10.

By all means, check for the interface first. If that's all you want to support, fine. If you want to go that extra mile, you'd need to perform steps like the compiler would, as in check for the appropriate methods and return types. Here's a thoroughly untested draft of an implementation.

bool IsEnumerable(object obj)
{
    if (obj is IEnumerable)
        return true;

    var info = obj.GetType().GetMethod("GetEnumerator");
    if (info != null)
    {
        if (info.ReturnType != null)
        {
            var moveNextMethod = info.ReturnType.GetMethod("MoveNext");
            if (moveNextMethod != null && moveNextMethod.ReturnType == typeof(bool))
            {
                var currentProperty = info.ReturnType.GetProperty("Current");
                if (currentProperty != null)
                    return true;
            }
        }
    }

    return false;
}

Some quick tests in LinqPad, but by no means exhaustive...

IsEnumerable(new CustomCollection()).Dump(); // true
IsEnumerable(1).Dump(); // false 
IsEnumerable(new List<int>()).Dump(); // true

Upvotes: 1

Paul Sonier
Paul Sonier

Reputation: 39520

The IEnumerable interface determines whether or not something is enumerable.

Upvotes: 0

ChrisWue
ChrisWue

Reputation: 19070

Cast it into IEnumerable:

var list = someVariable as IEnumerable;
if (list != null)
{
    ...
}

Upvotes: 3

devdigital
devdigital

Reputation: 34369

GetEnumerator() is defined on the IEnumerable interface, so:

if (obj is IEnumerable) 
{ 
   ... 
}

Upvotes: 1

CodesInChaos
CodesInChaos

Reputation: 108880

Check if it implements IEnumerable. IEnumerable<T> derives from IEnumerable, so any generic collection implements IEnumerable too.

if you have a type you can use Type.IsAssignableFrom if you have an instance you can use the is/as operators.

Upvotes: 0

Richard Szalay
Richard Szalay

Reputation: 84824

if (object is IEnumerable)
{
    foreach(var value in (IEnumerable)object)
    {
        // ...
    }
}

Upvotes: 4

Related Questions