Вопрос

Есть ли способ выполнить итерацию (предпочтительно через foreach) по коллекции с использованием отражения?Я перебираю свойства объекта с помощью отражения, и когда программа переходит к типу, который является коллекцией, я бы хотел, чтобы она перебирала содержимое коллекции и могла получить доступ к объектам в коллекции.

На данный момент у меня есть атрибут, установленный для всех моих свойств, с флагом IsCollection, установленным в true для свойств, которые являются коллекциями.Мой код проверяет наличие этого флага, и если это true, он получает Тип, используя отражение.Есть ли способ каким-либо образом вызвать GetEnumerator или Items в коллекции, чтобы иметь возможность перебирать элементы?

Это было полезно?

Решение

У меня была эта проблема, но вместо того, чтобы использовать отражение, я в итоге просто проверил, было ли оно IEnumerable.Все коллекции реализуют это.

if (item is IEnumerable)
{
    foreach (object o in (item as IEnumerable))
    {

    }
} else {
   // reflect over item
}

Другие советы

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

Вот небольшая функция, которую я использую, чтобы определить, является ли объект коллекцией (которая также будет перечислимой, поскольку ICollection также является IEnumerable).

    public bool isCollection(object o)
    {
        return typeof(ICollection).IsAssignableFrom(o.GetType())
            || typeof(ICollection<>).IsAssignableFrom(o.GetType());
    }

Просто получите значение свойства, а затем преобразуйте его в IEnumerable.Вот некоторый (непроверенный) код, который даст вам представление:

ClassWithListProperty obj = new ClassWithListProperty();
obj.List.Add(1);
obj.List.Add(2);
obj.List.Add(3);

Type type = obj.GetType();
PropertyInfo listProperty = type.GetProperty("List", BindingFlags.Public);
IEnumerable listObject = (IEnumerable) listProperty.GetValue(obj, null);

foreach (int i in listObject)
    Console.Write(i); // should print out 123

Лучшее, что вы, вероятно, могли бы сделать, это проверить, реализует ли объект определенные интерфейсы коллекции - вероятно, IEnumerable - это все, что вам нужно.Тогда это просто вопрос вызова GetEnumerator() вне объекта и использования IEnumerator .MoveNext() и IEnumerator .Текущий, чтобы проложить свой путь по коллекции.

Это не поможет вам, если коллекция не реализует эти интерфейсы, но если это так, то, я полагаю, это не такая уж большая коллекция.

Просто для информации, может быть, это кому-то поможет...У меня был класс с вложенными классами и коллекцией некоторых других классов.Я хотел сохранить значения свойств класса, а также вложенные классы и коллекцию классов.Мой код выглядит следующим образом:

 public void LogObject(object obj, int indent)
    {
        if (obj == null) return;
        string indentString = new string(' ', indent);
        Type objType = obj.GetType();
        PropertyInfo[] properties = objType.GetProperties();

        foreach (PropertyInfo property in properties)
        {
            Type tColl = typeof(ICollection<>);
            Type t = property.PropertyType;
            string name = property.Name;


            object propValue = property.GetValue(obj, null); 
            //check for nested classes as properties
            if (property.PropertyType.Assembly == objType.Assembly)
            {
                string _result = string.Format("{0}{1}:", indentString, property.Name);
                log.Info(_result);
                LogObject(propValue, indent + 2);
            }
            else
            {
                string _result = string.Format("{0}{1}: {2}", indentString, property.Name, propValue);
                log.Info(_result);
            }

            //check for collection
            if (t.IsGenericType && tColl.IsAssignableFrom(t.GetGenericTypeDefinition()) ||
                t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == tColl))
            {
                //var get = property.GetGetMethod();
                IEnumerable listObject = (IEnumerable)property.GetValue(obj, null);
                if (listObject != null)
                {
                    foreach (object o in listObject)
                    {
                        LogObject(o, indent + 2);
                    }
                }
            }
        }
    }

An вызвал эту функцию

LogObject(obj, 0);

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

Когда вы используете отражение, вы не обязательно используете экземпляр этого объекта.Вам нужно было бы создать экземпляр такого типа, чтобы иметь возможность выполнять итерации по свойствам объекта.Поэтому, если вы используете отражение, используйте ConstructorInfo.Метод Invoke() (?) для создания нового экземпляра или указания на экземпляр типа.

Я бы посмотрел на тип.Метод FindInterfaces.Это позволяет отфильтровать интерфейсы, реализованные данным типом.Как в PropertyInfo.PropertyType.Найдите интерфейсы (filterMethod, filterObjects).Вы можете выполнить фильтрацию по IEnumerable и посмотреть, будут ли возвращены какие-либо результаты.В документации по методу MSDN есть отличный пример.

Если вы используете не экземпляр объекта, а скорее Тип, вы можете использовать следующее:

// type is IEnumerable
if (type.GetInterface("IEnumerable") != null)
{
}

Довольно простым подходом было бы ввести приведение объекта как коллекции и напрямую использовать его.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top