Pregunta

¿Hay alguna manera de iterar (preferiblemente a través de foreach) sobre una colección usando la reflexión?Estoy iterando sobre las propiedades de un objeto usando la reflexión, y cuando el programa llega a un tipo que es una colección, me gustaría que itere sobre el contenido de la colección y pueda acceder a los objetos de la colección.

En este momento tengo un atributo establecido en todas mis propiedades, con un indicador IsCollection establecido en verdadero en las propiedades que son colecciones.Mi código busca esta bandera y, si es verdadera, obtiene el Tipo usando la reflexión.¿Hay alguna manera de invocar GetEnumerator o Items de alguna manera en una colección para poder iterar sobre los elementos?

¿Fue útil?

Solución

Tuve este problema, pero en lugar de usar la reflexión, terminé simplemente verificando si era IEnumerable.Todas las colecciones implementan eso.

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

    }
} else {
   // reflect over item
}

Otros consejos

Intenté utilizar una técnica similar a la que sugirió Darren, sin embargo, tenga en cuenta que no solo las colecciones implementan IEnumerable. string por ejemplo, también es IEnumerable y iterará sobre los caracteres.

Aquí hay una pequeña función que estoy usando para determinar si un objeto es una colección (que también será enumerable ya que ICollection también es IEnumerable).

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

Simplemente obtenga el valor de la propiedad y luego conviértalo en un IEnumerable.Aquí hay un código (no probado) para darle una idea:

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

Lo mejor que podría hacer probablemente sería verificar si el objeto implementa ciertas interfaces de colección; probablemente IEnumerable sería todo lo que necesita.Entonces es solo cuestión de llamar a GetEnumerator() fuera del objeto y usar IEnumerator.MoveNext() e IEnumerator.Current para avanzar a través de la colección.

Esto no le ayudará si la colección no implementa esas interfaces, pero si ese es el caso, supongo que no es una gran colección.

Solo para información tal vez a alguien le sirva...Tenía una clase con clases anidadas y una colección de otras clases.Quería guardar los valores de propiedad de la clase, así como las clases anidadas y la colección de clases.Mi código es el siguiente:

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

Una llamada esta función

LogObject(obj, 0);

Sin embargo, tengo algunas estructuras dentro de mis clases y necesito descubrir cómo obtener sus valores.Además, tengo una lista.Necesito obtener su valor también....Publicaré si actualizo mi código.

Cuando usas la reflexión, no necesariamente estás usando una instancia de ese objeto.Tendría que crear una instancia de ese tipo para poder iterar a través de las propiedades del objeto.Entonces, si está utilizando la reflexión, use el método ConstructorInfo.Invoke() (?) para crear una nueva instancia o apuntar a una instancia del tipo.

Yo miraría el método Type.FindInterfaces.Esto puede filtrar las interfaces implementadas por un tipo determinado.Como en PropertyInfo.PropertyType.FindInterfaces(filterMethod, filterObjects).Puede filtrar por IEnumerable y ver si se devuelve algún resultado.MSDN tiene un gran ejemplo en la documentación del método.

Si no estás usando una instancia del objeto sino más bien un Tipo, puedes usar lo siguiente:

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

Un enfoque bastante sencillo sería escribir el objeto como colección y usarlo directamente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top