Domanda

Esiste un modo per scorrere (preferibilmente foreach) su una raccolta usando la riflessione? Sto iterando sulle proprietà di un oggetto usando reflection, e quando il programma arriva a un tipo che è una raccolta, mi piacerebbe iterare sui contenuti della raccolta e poter accedere agli oggetti nella raccolta.

Al momento ho un attributo impostato su tutte le mie proprietà, con un flag IsCollection impostato su true sulle proprietà che sono raccolte. Il mio codice verifica la presenza di questo flag e, se è vero, ottiene il Tipo usando la riflessione. C'è un modo per invocare GetEnumerator o gli elementi in qualche modo su una raccolta per poter scorrere gli elementi?

È stato utile?

Soluzione

Ho avuto questo problema, ma invece di usare la riflessione, ho finito per controllare se fosse IEnumerable. Tutte le raccolte lo implementano.

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

    }
} else {
   // reflect over item
}

Altri suggerimenti

Ho provato ad usare una tecnica simile a quella suggerita da Darren, ma fai attenzione che non solo le raccolte implementano IEnumerable. string per esempio è anche IEnumerable e ripeterà i caratteri.

Ecco una piccola funzione che sto usando per determinare se un oggetto è una raccolta (che sarà enumerabile anche dal momento che ICollection è anche IEnumerable).

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

Basta ottenere il valore della proprietà e quindi eseguirne il cast in un IEnumerable. Ecco un po 'di codice (non testato) per darti un'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

Il meglio che probabilmente potresti fare sarebbe verificare se l'oggetto implementa determinate interfacce di raccolta - probabilmente IEnumerable sarebbe tutto ciò di cui hai bisogno. Quindi si tratta solo di chiamare GetEnumerator () dall'oggetto e usare IEnumerator.MoveNext () e IEnumerator.Current per farti strada attraverso la raccolta.

Questo non ti aiuterà se la raccolta non implementa quelle interfacce, ma in tal caso non è proprio una gran raccolta, suppongo.

Solo per informazione potrebbe essere l'aiuto di qualcuno ... Ho tenuto una classe con classi nidificate e raccolta di alcune altre classi. Volevo salvare i valori delle proprietà della classe, nonché le classi nidificate e la raccolta di classi. Il mio codice è il seguente:

 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 chiamata a questa funzione

LogObject(obj, 0);

Tuttavia, ho alcune strutture all'interno delle mie classi e ho bisogno di capire come ottenere i loro valori. Inoltre, ne ho un po '. Devo anche ottenere il loro valore .... Pubblicherò se aggiorno il mio codice.

Quando usi la riflessione non stai necessariamente usando un'istanza di quell'oggetto. Dovresti creare un'istanza di quel tipo per poter iterare attraverso le proprietà dell'oggetto. Quindi, se si utilizza la riflessione, utilizzare il metodo ConstructorInfo.Invoke () (?) Per creare una nuova istanza o puntare a un'istanza del tipo.

Vorrei esaminare il metodo Type.FindInterfaces. Questo può filtrare le interfacce implementate da un determinato tipo. Come in PropertyInfo.PropertyType.FindInterfaces (filterMethod, filterObjects). Puoi filtrare per IEnumerable e vedere se vengono restituiti risultati. MSDN ha un ottimo esempio nella documentazione del metodo.

Se non si utilizza un'istanza dell'oggetto ma piuttosto un Tipo, è possibile utilizzare quanto segue:

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

Un approccio piuttosto semplice sarebbe quello di digitare cast l'oggetto come raccolta e usarlo direttamente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top