Mam klasę zawierającą kilka właściwości (wszystkie są ciągami znaków, jeśli ma to znaczenie).
Mam też listę, która zawiera wiele różnych instancji tej klasy.
Tworząc testy jednostkowe dla moich klas, zdecydowałem, że chcę przejść przez każdy obiekt na liście, a następnie przejść przez każdą właściwość tego obiektu ...
Pomyślałem, że zrobienie tego byłoby tak proste, jak ...
foreach (Object obj in theList)
{
foreach (Property theProperties in obj)
{
do some stufff!!;
}
}
Ale to nie zadziałało! :( Otrzymuję ten błąd ...
„Instrukcja foreach nie może działać na zmiennych typu 'Application.Object', ponieważ 'Application.Object' nie zawiera publicznej definicji dla 'GetEnumerator'”
Czy ktoś zna sposób na zrobienie tego bez mnóstwa ifów i pętli lub bez wchodzenia w nic zbyt skomplikowanego?
c#
properties
foreach
generic-list
Jammerz858
źródło
źródło
Odpowiedzi:
Spróbuj:
foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties()) { // do stuff here }
Należy również pamiętać, że
Type.GetProperties()
ma przeciążenie, które akceptuje zestaw flag powiązań, dzięki czemu można odfiltrować właściwości według różnych kryteriów, takich jak poziom dostępności, więcej szczegółów można znaleźć w witrynie MSDN: Metoda Type.GetProperties (BindingFlags) Wreszcie, nie zapomnij o dodaj odwołanie do zestawu „system.Reflection”.Na przykład, aby rozwiązać wszystkie właściwości publiczne:
foreach (var propertyInfo in obj.GetType() .GetProperties( BindingFlags.Public | BindingFlags.Instance)) { // do stuff here }
Daj mi znać, czy to działa zgodnie z oczekiwaniami.
źródło
Możesz przeglądać wszystkie nieindeksowane właściwości obiektu w następujący sposób:
var s = new MyObject(); foreach (var p in s.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) { Console.WriteLine(p.GetValue(s, null)); }
Ponieważ
GetProperties()
zwraca indeksatory, a także proste właściwości, przed wywołaniem potrzebny jest dodatkowy filtr,GetValue
aby wiedzieć, że można bezpiecznie przekazaćnull
jako drugi parametr.Konieczne może być dalsze zmodyfikowanie filtru w celu wyeliminowania właściwości tylko do zapisu i niedostępnych w inny sposób.
źródło
null
funkcją getter, ale jestem pewien, że OP dowie się, jak uzyskać tylko te właściwości, których potrzebuje.Jesteś już prawie na miejscu, wystarczy pobrać właściwości z typu, zamiast oczekiwać, że właściwości będą dostępne w formie kolekcji lub worka z nieruchomościami:
var property in obj.GetType().GetProperties()
Stamtąd możesz uzyskać dostęp w następujący sposób :
property.Name property.GetValue(obj, null)
Z
GetValue
drugiego parametru pozwoli na określenie wartości indeksu, które będą pracować z właściwości powrocie kolekcji - ponieważ ciąg jest zbiorem znaków, można również określić indeks zwrócić charakter, jeśli musi być.źródło
Pewnie nie ma problemu:
foreach(object item in sequence) { if (item == null) continue; foreach(PropertyInfo property in item.GetType().GetProperties()) { // do something with the property } }
źródło
if (item == null) continue;
Osobiście myślę, że jeśli w tym momencie otrzymałeś obiekt zerowy, coś poszło nie tak dużo wcześniej i właśnie tam powinno być sprawdzanie poprawności, czy się mylę?Użyj do tego odbicia
źródło
Szukałem odpowiedzi na podobne pytanie na tej stronie, napisałem odpowiedzi na kilka podobnych pytań, które mogą pomóc osobom wchodzącym na tę stronę.
Lista klas
Klasa List <T> reprezentuje listę obiektów, do których można uzyskać dostęp za pomocą indeksu. Znajduje się w przestrzeni nazw System.Collection.Generic. Klasy List można używać do tworzenia kolekcji różnych typów, takich jak liczby całkowite, łańcuchy itp. Klasa List udostępnia również metody wyszukiwania, sortowania i manipulowania listami.
Klasa z właściwością :
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); } }
OR, klasa z polem :
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); } }
OR, lista obiektów (bez tych samych komórek):
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); } }
LUB, Lista obiektów (musi mieć te same komórki):
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); } }
OR, Lista obiektów (z kluczem):
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); } }
LUB, Lista słowników
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); } }
Powodzenia..
źródło
Małe słowo przestrogi, jeśli „zrób coś” oznacza aktualizację wartości rzeczywistej właściwości, którą odwiedzasz ORAZ jeśli na ścieżce od obiektu głównego do odwiedzanej właściwości znajduje się właściwość typu struct, zmiana dokonana w tej właściwości nie zostaną odzwierciedlone w obiekcie głównym.
źródło
Rozwiązanie typu „kopiuj-wklej” (metody rozszerzające) oparte głównie na wcześniejszych odpowiedziach na to pytanie.
Prawidłowo obsługuje również IDicitonary (ExpandoObject / dynamic), co jest często potrzebne w przypadku tych odzwierciedlonych rzeczy.
Niezalecane do użytku w ciasnych pętlach i innych gorących ścieżkach. W takich przypadkach będziesz potrzebować trochę kompilacji pamięci podręcznej / IL emitowania / wyrażenia.
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()); }
źródło
Nie mogłem znaleźć żadnego z powyższych sposobów, ale to zadziałało. Nazwa użytkownika i hasło dla DirectoryEntry są opcjonalne.
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; }
źródło