Доступ к коллекции через отражение - PullRequest
29 голосов
/ 19 сентября 2008

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

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

Ответы [ 9 ]

35 голосов
/ 19 сентября 2008

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

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

    }
} else {
   // reflect over item
}
29 голосов
/ 14 февраля 2009

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

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

    public bool isCollection(object o)
    {
        return typeof(ICollection).IsAssignableFrom(o.GetType())
            || typeof(ICollection<>).IsAssignableFrom(o.GetType());
    }
8 голосов
/ 19 сентября 2008

Просто получите значение свойства и затем приведите его в 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
2 голосов
/ 23 мая 2012

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

 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, у меня есть немного времени. Мне также нужно узнать их значение ... Я буду публиковать сообщения, если обновлю свой код.

2 голосов
/ 19 сентября 2008

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

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

0 голосов
/ 10 июня 2010

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

// type is IEnumerable
if (type.GetInterface("IEnumerable") != null)
{
}
0 голосов
/ 20 февраля 2009

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

0 голосов
/ 19 сентября 2008

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

0 голосов
/ 19 сентября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...