Доступ к коллекции через отражение

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

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

19.09.2008 19:06:01
9 ОТВЕТОВ
РЕШЕНИЕ

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

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

    }
} else {
   // reflect over item
}
36
19.09.2008 19:12:19
как в не нужно, вы проверили это с таким простым приведением в порядке
ShuggyCoUk 14.02.2009 19:52:45
приведение с as выполняется быстрее, чем (IEnumerable).
Darren Kopp 17.02.2009 16:34:46
Это может быть более эффективным: var enumItem = item as IEnumerable; if (enumItem! = null) // делать foreach
Bob Wintemberg 27.03.2012 11:51:55

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

0
19.09.2008 19:11:35

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

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

2
19.09.2008 19:11:48

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

0
30.08.2016 15:15:03

Просто получите значение свойства и затем приведите его в 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
8
19.09.2008 19:22:24

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

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

    public bool isCollection(object o)
    {
        return typeof(ICollection).IsAssignableFrom(o.GetType())
            || typeof(ICollection<>).IsAssignableFrom(o.GetType());
    }
29
14.02.2009 15:24:49

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

0
20.02.2009 16:17:13

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

// type is IEnumerable
if (type.GetInterface("IEnumerable") != null)
{
}
0
10.06.2010 07:37:09

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

 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);
                    }
                }
            }
        }
    }

Называется эта функция

LogObject(obj, 0);

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

3
23.05.2012 19:16:39