Ответы, предлагающие вам проверить, является ли объект IEnumerable
разумным местом. В подавляющем большинстве случаев ваша коллекция или объект будут реализовывать этот интерфейс, если он поддерживает перечисление. Но это не обязательно.
Для того, чтобы что-то перечислить в foreach
, ему действительно нужно только предоставить метод GetEnumerator()
, который возвращает объект с подходящими реализациями MoveNext()
и Current
. Рассмотрим что-то вроде:
class CustomCollection
{
public CustomEnumerator GetEnumerator()
{
return new CustomEnumerator();
}
}
class CustomEnumerator
{
public bool MoveNext()
{
return (++this.Current <= 10);
}
public int Current { get; private set; }
}
Вы можете поместить new CustomCollection()
в цикл и получить значения 1..10.
Конечно, сначала проверьте интерфейс. Если это все, что вы хотите поддержать, хорошо. Если вы хотите пройти лишнюю милю, вам нужно будет выполнить шаги, аналогичные действиям компилятора, как при проверке соответствующих методов и возвращаемых типов. Вот полностью непроверенный проект реализации.
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;
}
Некоторые быстрые тесты в LinqPad, но ни в коем случае не исчерпывающие ...
IsEnumerable(new CustomCollection()).Dump(); // true
IsEnumerable(1).Dump(); // false
IsEnumerable(new List<int>()).Dump(); // true