2008-09-19 5 views
28

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

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

ответ

33

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

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

    } 
} else { 
    // reflect over item 
} 
+2

как в случае необходимости, вы проверили его, так что простое отличное отличное – ShuggyCoUk 2009-02-14 19:52:45

+1

литье с чем быстрее, чем (IEnumerable). – 2009-02-17 16:34:46

0

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

2

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

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

0

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

8

Просто получите значение свойства, а затем введите его в 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 
29

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

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

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

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

0

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

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

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

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

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

Смежные вопросы