Reputation: 15340
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
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
Reputation: 39520
The IEnumerable
interface determines whether or not something is enumerable.
Upvotes: 0
Reputation: 19070
Cast it into IEnumerable
:
var list = someVariable as IEnumerable;
if (list != null)
{
...
}
Upvotes: 3
Reputation: 34369
GetEnumerator()
is defined on the IEnumerable
interface, so:
if (obj is IEnumerable)
{
...
}
Upvotes: 1
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
Reputation: 84824
if (object is IEnumerable)
{
foreach(var value in (IEnumerable)object)
{
// ...
}
}
Upvotes: 4