Frage Zugreifen auf eine Sammlung durch Reflektion


Gibt es eine Möglichkeit, (vorzugsweise durch foreach) über eine Sammlung durch Reflexion zu iterieren? Ich überspringe die Eigenschaften in einem Objekt mit Reflektion, und wenn das Programm zu einem Typ kommt, der eine Sammlung ist, möchte ich, dass es über den Inhalt der Sammlung iteriert und auf die Objekte in der Sammlung zugreifen kann.

Im Moment habe ich ein Attribut für alle meine Eigenschaften festgelegt, wobei ein IsCollection-Flag in den Eigenschaften, die Sammlungen sind, auf true gesetzt ist. Mein Code prüft auf dieses Flag und wenn es wahr ist, erhält es den Typ mit Reflektion. Gibt es eine Möglichkeit, GetEnumerator oder Elemente auf einer Sammlung irgendwie aufzurufen, um über die Elemente zu iterieren?


29
2017-09-19 19:06


Ursprung


Antworten:


Ich hatte dieses Problem, aber anstatt Reflektion zu verwenden, überprüfte ich nur, ob es IEnumerable war. Alle Sammlungen implementieren das.

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

    }
} else {
   // reflect over item
}

34
2017-09-19 19:12



Ich habe versucht, eine ähnliche Technik zu verwenden, wie Darren vorgeschlagen hat, aber hüte dich davor, dass nicht nur Sammlungen IEnumerable implementieren. string Zum Beispiel ist auch IEnumerable und wird über die Zeichen iterieren.

Hier ist eine kleine Funktion, die ich verwende, um zu bestimmen, ob ein Objekt eine Sammlung ist (die auch aufzählbar sein wird, da ICollection auch IEnumerable ist).

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

29
2018-02-14 15:06



Holen Sie sich einfach den Wert der Eigenschaft und wandeln Sie ihn in ein IEnumerable um. Hier ist ein (nicht getesteter) Code, um Ihnen eine Idee zu geben:

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
2017-09-19 19:22



Das Beste, was Sie wahrscheinlich tun könnten, wäre zu überprüfen, ob das Objekt bestimmte Sammelschnittstellen implementiert - wahrscheinlich würde IEnumerable alles sein, was Sie brauchen. Dann ist es nur eine Frage von GetEnumerator () von dem Objekt abzurufen und IEnumerator.MoveNext () und IEnumerator.Current zu verwenden, um sich durch die Auflistung zu arbeiten.

Dies wird Ihnen nicht helfen, wenn die Sammlung diese Schnittstellen nicht implementiert, aber wenn das der Fall ist, ist es nicht wirklich eine Sammlung, nehme ich an.


2
2017-09-19 19:11



Nur zur Information kann es jemandes Hilfe sein ... Ich hatte eine Klasse mit verschachtelten Klassen und Sammlung einiger anderer Klassen. Ich wollte die Eigenschaftswerte der Klasse sowie verschachtelte Klassen und Klassensammlungen speichern. Mein Code ist wie folgt:

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

Ein nannte diese Funktion

LogObject(obj, 0);

Jedoch habe ich einige Strukturen in meinen Klassen und ich muss herausfinden, wie man ihre Werte bekommt. Moreoevr, ich habe etwas LIst. Ich muss ihren Wert auch bekommen .... Ich werde veröffentlichen, wenn ich meinen Code aktualisiere.


2
2018-05-23 19:16



Wenn Sie Reflexion verwenden, verwenden Sie nicht unbedingt eine Instanz dieses Objekts. Sie müssten eine Instanz dieses Typs erstellen, um die Eigenschaften des Objekts durchlaufen zu können. Wenn Sie also Reflektion verwenden, verwenden Sie die Methode ConstructorInfo.Invoke () (?), Um eine neue Instanz zu erstellen oder auf eine Instanz des Typs zu zeigen.


0
2017-09-19 19:11



Ich würde die Type.FindInterfaces-Methode betrachten. Dies kann die Schnittstellen filtern, die von einem bestimmten Typ implementiert werden. Wie in PropertyInfo.PropertyType.FindInterfaces (filterMethod, filterObjects). Sie können nach IEnumerable filtern und sehen, ob Ergebnisse zurückgegeben werden. MSDN hat ein großartiges Beispiel in der Methodendokumentation.


0
2018-02-20 16:17