Tengo una clase que contiene varias propiedades (todas son cadenas si hay alguna diferencia).
También tengo una lista, que contiene muchas instancias diferentes de la clase.
Mientras creaba algunas pruebas unitarias para mis clases, decidí que quería recorrer cada objeto en la lista y luego recorrer cada propiedad de ese objeto ...
Pensé que hacer esto sería tan simple como ...
foreach (Object obj in theList)
{
foreach (Property theProperties in obj)
{
do some stufff!!;
}
}
¡Pero esto no funcionó! :( Recibo este error ...
"La instrucción foreach no puede operar en variables de tipo 'Application.Object' porque 'Application.Object' no contiene una definición pública para 'GetEnumerator'"
¿Alguien conoce una forma de hacer esto sin toneladas de ifs y bucles o sin meterse en nada demasiado complejo?
c#
properties
foreach
generic-list
Jammerz858
fuente
fuente
Respuestas:
Prueba esto:
foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties()) { // do stuff here }
También tenga en cuenta que
Type.GetProperties()
tiene una sobrecarga que acepta un conjunto de indicadores de vinculación para que pueda filtrar propiedades en un criterio diferente como el nivel de accesibilidad, consulte MSDN para obtener más detalles: Método Type.GetProperties (BindingFlags) Por último, pero no menos importante, no olvide agregue la referencia de ensamblaje "system.Reflection".Por ejemplo, para resolver todas las propiedades públicas:
foreach (var propertyInfo in obj.GetType() .GetProperties( BindingFlags.Public | BindingFlags.Instance)) { // do stuff here }
Por favor, avíseme si esto funciona como se esperaba.
fuente
Puede recorrer todas las propiedades no indexadas de un objeto como este:
var s = new MyObject(); foreach (var p in s.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) { Console.WriteLine(p.GetValue(s, null)); }
Dado que
GetProperties()
devuelve indexadores , así como propiedades simples, necesita un filtro adicional antes de llamarGetValue
para saber que es seguro pasarnull
como segundo parámetro.Es posible que deba modificar más el filtro para eliminar las propiedades de solo escritura y otras inaccesibles.
fuente
null
getter, pero estoy seguro de que OP descubrirá cómo obtener solo las propiedades que necesita.Ya casi está allí, solo necesita obtener las propiedades del tipo, en lugar de esperar que las propiedades sean accesibles en forma de colección o bolsa de propiedades:
var property in obj.GetType().GetProperties()
Desde allí puedes acceder así :
property.Name property.GetValue(obj, null)
Con
GetValue
el segundo parámetro le permitirá especificar valores de índice, que funcionarán con propiedades que devuelvan colecciones; dado que una cadena es una colección de caracteres, también puede especificar un índice para devolver un carácter si es necesario.fuente
Claro, no hay problema:
foreach(object item in sequence) { if (item == null) continue; foreach(PropertyInfo property in item.GetType().GetProperties()) { // do something with the property } }
fuente
if (item == null) continue;
personalmente, creo que si tienes un objeto nulo en ese momento, algo salió mal mucho antes y ahí es donde debería estar la validación, ¿o estoy equivocado?Usa Reflection para hacer esto
fuente
Busqué la respuesta a una pregunta similar en esta página, escribí las respuestas a varias preguntas similares que pueden ayudar a las personas que ingresan a esta página.
Lista de clase
La clase List <T> representa la lista de objetos a los que se puede acceder por índice. Viene bajo el espacio de nombres System.Collection.Generic. La clase List se puede usar para crear una colección de diferentes tipos como enteros, cadenas, etc. La clase List también proporciona los métodos para buscar, ordenar y manipular listas.
Clase con propiedad :
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); } }
O, Clase con campo :
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); } }
O, Lista de objetos (sin las mismas celdas):
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); } }
O, Lista de objetos (debe tener las mismas celdas):
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); } }
O, Lista de objetos (con clave):
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); } }
O, lista de diccionario
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); } }
Buena suerte..
fuente
Una pequeña advertencia, si "hacer algunas cosas" significa actualizar el valor de la propiedad real que visita Y si hay una propiedad de tipo de estructura a lo largo de la ruta desde el objeto raíz a la propiedad visitada, el cambio que realizó en la propiedad será no reflejarse en el objeto raíz.
fuente
Una solución de copiar y pegar (métodos de extensión) basada principalmente en respuestas anteriores a esta pregunta.
También maneja correctamente IDicitonary (ExpandoObject / dynamic) que a menudo se necesita cuando se trata de este material reflejado.
No se recomienda su uso en bucles estrechos y otros caminos calientes. En esos casos, necesitará alguna compilación de árbol de expresión / emisión de IL / caché.
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()); }
fuente
No pude conseguir que ninguna de las formas anteriores funcionara, pero funcionó. El nombre de usuario y la contraseña de DirectoryEntry son opcionales.
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; }
fuente