В C # можно определить, есть ли у переменной перечислитель - PullRequest
0 голосов
/ 14 июля 2011

Я пытаюсь написать общую процедуру сравнения. Тем не менее, некоторые из предметов в моем классе находятся в коллекциях, и мне нужно перечислить, чтобы сравнить.

Есть ли простой способ, без блока try / catch определить, поддерживает ли переменная GetEnumerator ()

Ответы [ 6 ]

4 голосов
/ 14 июля 2011
if (object is IEnumerable)
{
    foreach(var value in (IEnumerable)object)
    {
        // ...
    }
}
3 голосов
/ 14 июля 2011

Измените это на IEnumerable:

var list = someVariable as IEnumerable;
if (list != null)
{
    ...
}
1 голос
/ 14 июля 2011

Ответы, предлагающие вам проверить, является ли объект 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
1 голос
/ 14 июля 2011

GetEnumerator() определяется на интерфейсе IEnumerable, поэтому:

if (obj is IEnumerable) 
{ 
   ... 
}
0 голосов
/ 14 июля 2011

Интерфейс IEnumerable определяет, является ли что-либо перечисляемым.

0 голосов
/ 14 июля 2011

Проверьте, реализует ли он IEnumerable.IEnumerable<T> происходит от IEnumerable, поэтому любая универсальная коллекция также реализует IEnumerable.

если у вас есть тип, вы можете использовать Type.IsAssignableFrom, если у вас есть экземпляр, вы можете использовать is / as операторов.

...