c # foreach (Eigenschaft im Objekt)… Gibt es eine einfache Möglichkeit, dies zu tun?


89

Ich habe eine Klasse, die mehrere Eigenschaften enthält (alle sind Zeichenfolgen, wenn es einen Unterschied macht).
Ich habe auch eine Liste, die viele verschiedene Instanzen der Klasse enthält.

Während ich einige Komponententests für meine Klassen erstellte, entschied ich, dass ich jedes Objekt in der Liste durchlaufen und dann jede Eigenschaft dieses Objekts durchlaufen wollte ...

Ich dachte, das wäre so einfach wie ...

foreach (Object obj in theList)
{
     foreach (Property theProperties in obj)
     {
         do some stufff!!;
     }
}

Aber das hat nicht funktioniert! :( Ich bekomme diesen Fehler ...

"foreach-Anweisung kann nicht mit Variablen vom Typ 'Application.Object' arbeiten, da 'Application.Object' keine öffentliche Definition für 'GetEnumerator' enthält."

Kennt jemand einen Weg, dies ohne jede Menge Wenn und Schleifen zu tun oder ohne auf etwas zu Komplexes einzugehen?


5
Bitte sagen Sie in Zukunft in einer Frage nicht "Es funktioniert nicht". Geben Sie stattdessen das Problem an, das Sie haben (Compilerfehler usw.). Vielen Dank!
Robert Harvey

2
Aktualisiert! Vielen Dank für die Heads-up Robert
Jammerz858

Antworten:


143

Probieren Sie es aus:

foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties())
{
   // do stuff here
}

Beachten Sie auch, dass Type.GetProperties()es eine Überladung gibt, die eine Reihe von Bindungsflags akzeptiert, sodass Sie Eigenschaften nach anderen Kriterien wie der Barrierefreiheit herausfiltern können. Weitere Informationen finden Sie unter MSDN: Type.GetProperties-Methode (BindingFlags) Vergessen Sie nicht, dies zu vergessen Fügen Sie die Assemblyreferenz "system.Reflection" hinzu.

Zum Beispiel, um alle öffentlichen Eigenschaften aufzulösen:

foreach (var propertyInfo in obj.GetType()
                                .GetProperties(
                                        BindingFlags.Public 
                                        | BindingFlags.Instance))
{
   // do stuff here
}

Bitte lassen Sie mich wissen, ob dies wie erwartet funktioniert.


3
Gibt es eine Möglichkeit, den Wert jeder Eigenschaft zu ermitteln, sobald Sie die Objekteigenschaften im Griff haben? dh ein Name oder eine Postleitzahl zum Beispiel
JsonStatham

35

Sie können alle nicht indizierten Eigenschaften eines Objekts wie folgt durchlaufen:

var s = new MyObject();
foreach (var p in s.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) {
    Console.WriteLine(p.GetValue(s, null));
}

Da GetProperties()kehrt Indexer sowie einfache Eigenschaften, benötigen Sie einen zusätzlichen Filter vor dem Aufruf GetValuezu wissen , dass es sicher ist , passieren nullals zweiten Parameter.

Möglicherweise müssen Sie den Filter weiter modifizieren, um schreibgeschützte und ansonsten unzugängliche Eigenschaften auszusortieren.


+1, um nur etwas mit den Eigenschaften zu tun, die tatsächlich verwendet werden können. Möglicherweise möchten Sie auch schreibgeschützte Eigenschaften herausfiltern.

@hvd Es ist ein ausgezeichneter Punkt für die Nur-Schreib-Eigenschaften! Ich habe sie fast vergessen. Mein Code stürzt ab, wenn er auf eine Eigenschaft mit nullGetter stößt , aber ich bin sicher, dass OP herausfinden wird, wie nur die Eigenschaften abgerufen werden, die er benötigt.
Dasblinkenlight

26

Sie sind fast da, Sie müssen nur die Eigenschaften des Typs abrufen, anstatt zu erwarten, dass die Eigenschaften in Form einer Sammlung oder einer Eigenschaftstasche zugänglich sind:

var property in obj.GetType().GetProperties()

Von dort aus können Sie wie folgt zugreifen :

property.Name
property.GetValue(obj, null)

Mit GetValuedem zweiten Parameter können Sie Indexwerte angeben, die mit Eigenschaften funktionieren, die Sammlungen zurückgeben. Da eine Zeichenfolge eine Sammlung von Zeichen ist, können Sie auch einen Index angeben, um bei Bedarf ein Zeichen zurückzugeben.


1
Habe ich jemanden verärgert? Ich bin offen dafür zu wissen, was daran falsch ist, sonst könnte ich nie lernen.
Grant Thomas

Sie haben wahrscheinlich die Abwertung erhalten, als Ihr Code falsch war (vor Ihrer Ninja-Bearbeitung).
Robert Harvey

20

Sicher kein Problem:

foreach(object item in sequence)
{
    if (item == null) continue;
    foreach(PropertyInfo property in item.GetType().GetProperties())
    {
        // do something with the property
    }
}

Warum hast du diese Zeile hinzugefügt? if (item == null) continue;Ich persönlich denke, wenn Sie zu diesem Zeitpunkt ein Null-Objekt haben, ist viel früher etwas schiefgegangen, und dort sollte die Validierung sein, oder irre ich mich?
Dementic

@Dementic: Sicher, wir könnten sagen, dass die Sequenz Nicht-Null-Referenzen enthalten muss.
Eric Lippert

3

Verwenden Sie dazu Reflection

SomeClass A = SomeClass(...)
PropertyInfo[] properties = A.GetType().GetProperties();

0

Ein kleines Wort der Vorsicht: Wenn "einige Dinge tun" bedeutet, den Wert der tatsächlich besuchten Eigenschaft zu aktualisieren, UND wenn sich auf dem Pfad vom Stammobjekt zur besuchten Eigenschaft eine Eigenschaft vom Typ Struktur befindet, wird die Änderung, die Sie an der Eigenschaft vorgenommen haben, geändert nicht auf dem Stammobjekt reflektiert werden.


0

Ich konnte keine der oben genannten Arbeitsmethoden finden, aber das hat funktioniert. Der Benutzername und das Kennwort für DirectoryEntry sind optional.

   private List<string> getAnyDirectoryEntryPropertyValue(string userPrincipalName, string propertyToSearchFor)
    {
        List<string> returnValue = new List<string>();
        try
        {
            int index = userPrincipalName.IndexOf("@");
            string originatingServer = userPrincipalName.Remove(0, index + 1);
            string path = "LDAP://" + originatingServer; //+ @"/" + distinguishedName;
            DirectoryEntry objRootDSE = new DirectoryEntry(path, PSUsername, PSPassword);
            var objSearcher = new System.DirectoryServices.DirectorySearcher(objRootDSE);
            objSearcher.Filter = string.Format("(&(UserPrincipalName={0}))", userPrincipalName);
            SearchResultCollection properties = objSearcher.FindAll();

            ResultPropertyValueCollection resPropertyCollection = properties[0].Properties[propertyToSearchFor];
            foreach (string resProperty in resPropertyCollection)
            {
                returnValue.Add(resProperty);
            }
        }
        catch (Exception ex)
        {
            returnValue.Add(ex.Message);
            throw;
        }

        return returnValue;
    }

0

Eine Copy-Paste-Lösung (Erweiterungsmethoden), die hauptsächlich auf früheren Antworten auf diese Frage basiert.

Behandelt auch IDicitonary (ExpandoObject / dynamic) richtig, was häufig benötigt wird, wenn mit diesen reflektierten Dingen umgegangen wird.

Nicht empfohlen für enge Schleifen und andere heiße Pfade. In diesen Fällen benötigen Sie eine Caching- / IL-Emit- / Ausdrucksbaumkompilierung.

    public static IEnumerable<(string Name, object Value)> GetProperties(this object src)
    {
        if (src is IDictionary<string, object> dictionary)
        {
            return dictionary.Select(x => (x.Key, x.Value));
        }
        return src.GetObjectProperties().Select(x => (x.Name, x.GetValue(src)));
    }

    public static IEnumerable<PropertyInfo> GetObjectProperties(this object src)
    {
        return src.GetType()
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => !p.GetGetMethod().GetParameters().Any());
    }

0

Ich habe auf dieser Seite nach der Antwort auf eine ähnliche Frage gesucht. Ich habe die Antworten auf mehrere ähnliche Fragen geschrieben, die Personen helfen können, die diese Seite betreten.

Klassenliste

Die Klasse List <T> repräsentiert die Liste der Objekte, auf die über den Index zugegriffen werden kann. Es fällt unter den System.Collection.Generic-Namespace. Die Listenklasse kann verwendet werden, um eine Sammlung verschiedener Typen wie Ganzzahlen, Zeichenfolgen usw. zu erstellen. Die Listenklasse bietet auch die Methoden zum Suchen, Sortieren und Bearbeiten von Listen.

Klasse mit Eigentum :

class TestClss
{
    public string id { set; get; }
    public string cell1 { set; get; }
    public string cell2 { set; get; }
}
var MyArray = new List<TestClss> {
    new TestClss() { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new TestClss() { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new TestClss() { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (PropertyInfo property in Item.GetType().GetProperties())
    {
        var Key = property.Name;
        var Value = property.GetValue(Item, null);
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

ODER Klasse mit Feld :

class TestClss
{
    public string id = "";
    public string cell1 = "";
    public string cell2 = "";
}
var MyArray = new List<TestClss> {
    new TestClss() { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new TestClss() { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new TestClss() { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (var fieldInfo in Item.GetType().GetFields())
    {
        var Key = fieldInfo.Name;
        var Value = fieldInfo.GetValue(Item);
    }

}

ODER, Liste der Objekte (ohne dieselben Zellen):

var MyArray = new List<object> {
    new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data", anotherCell = "" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (var props in Item.GetType().GetProperties())
    {
        var Key = props.Name;
        var Value = props.GetMethod.Invoke(Item, null).ToString();
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

ODER, Liste der Objekte (Sie müssen dieselben Zellen haben):

var MyArray = new[] {
    new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (var props in Item.GetType().GetProperties())
    {
        var Key = props.Name;
        var Value = props.GetMethod.Invoke(Item, null).ToString();
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

ODER Liste der Objekte (mit Schlüssel):

var MyArray = new {
    row1 = new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    row2 = new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    row3 = new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
// using System.ComponentModel;  for TypeDescriptor
foreach (PropertyDescriptor Item in TypeDescriptor.GetProperties(MyArray))
{
    string Rowkey = Item.Name;
    object RowValue = Item.GetValue(MyArray);
    Console.WriteLine("Row key is: {0}", Rowkey);
    foreach (var props in RowValue.GetType().GetProperties())
    {
        var Key = props.Name;
        var Value = props.GetMethod.Invoke(RowValue, null).ToString();
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

ODER Liste des Wörterbuchs

var MyArray = new List<Dictionary<string, string>>() {
    new Dictionary<string, string>() { { "id", "1" }, { "cell1", "cell 1 row 1 Data" }, { "cell2", "cell 2 row 1 Data" } },
    new Dictionary<string, string>() { { "id", "2" }, { "cell1", "cell 1 row 2 Data" }, { "cell2", "cell 2 row 2 Data" } },
    new Dictionary<string, string>() { { "id", "3" }, { "cell1", "cell 1 row 3 Data" }, { "cell2", "cell 2 row 3 Data" } }
};
foreach (Dictionary<string, string> Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (KeyValuePair<string, string> props in Item)
    {
        var Key = props.Key;
        var Value = props.Value;
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

Viel Glück..

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.