valores recorrer propiedades obtener objetos objeto net lista array c# properties iteration anonymous-types

recorrer - ¿Cómo puedo iterar sobre las propiedades de un objeto anónimo en C#?



recorrer propiedades de un objeto c# (6)

Quiero tomar un objeto anónimo como argumento para un método, y luego iterar sobre sus propiedades para agregar cada propiedad / valor a un ExpandoObject dinámico.

Entonces lo que necesito es ir de

new { Prop1 = "first value", Prop2 = SomeObjectInstance, Prop3 = 1234 }

para conocer los nombres y valores de cada propiedad y poder agregarlos al ExpandoObject .

¿Cómo logro esto?

Nota al margen: Esto se hará en muchas de mis pruebas unitarias (lo estoy utilizando para refactorizar una gran cantidad de basura en la configuración), por lo que el rendimiento es en cierta medida relevante. No sé lo suficiente sobre la reflexión como para decirlo con certeza, pero por lo que he entendido es un rendimiento bastante pesado, así que si es posible, preferiría evitarlo ...

Pregunta de seguimiento: Como dije, tomo este objeto anónimo como argumento para un método. ¿Qué tipo de datos debo usar en la firma del método? ¿Todas las propiedades estarán disponibles si uso object ?


Esta es una vieja pregunta, pero ahora deberías poder hacer esto con el siguiente código:

dynamic expObj = new ExpandoObject(); expObj.Name = "James Kirk"; expObj.Number = 34; // print the dynamically added properties // enumerating over it exposes the Properties and Values as a KeyValuePair foreach (KeyValuePair<string, object> kvp in expObj){ Console.WriteLine("{0} = {1} : Type: {2}", kvp.Key, kvp.Value, kvp.Value.GetType()); }

La salida se vería así:

Nombre = James Kirk: Tipo: System.String

Número = 34: Tipo: System.Int32


Reflexione sobre el objeto anónimo para obtener sus nombres y valores de propiedad, luego aproveche un ExpandoObject que realmente es un diccionario para poblarlo. Aquí hay un ejemplo, expresado como una prueba de unidad:

[TestMethod] public void ShouldBeAbleToConvertAnAnonymousObjectToAnExpandoObject() { var additionalViewData = new {id = "myControlId", css = "hide well"}; dynamic result = new ExpandoObject(); var dict = (IDictionary<string, object>)result; foreach (PropertyInfo propertyInfo in additionalViewData.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { dict[propertyInfo.Name] = propertyInfo.GetValue(additionalViewData, null); } Assert.AreEqual(result.id, "myControlId"); Assert.AreEqual(result.css, "hide well"); }


Un enfoque alternativo es usar DynamicObject lugar de ExpandoObject , y de esa manera solo tendrá la sobrecarga de hacer la reflexión si realmente intenta acceder a una propiedad desde el otro objeto.

public class DynamicForwarder : DynamicObject { private object _target; public DynamicForwarder(object target) { _target = target; } public override bool TryGetMember( GetMemberBinder binder, out object result) { var prop = _target.GetType().GetProperty(binder.Name); if (prop == null) { result = null; return false; } result = prop.GetValue(_target, null); return true; } }

Ahora solo hace la reflexión cuando realmente intentas acceder a la propiedad a través de un get dinámico. En el lado negativo, si accede repetidamente a la misma propiedad, tiene que hacer el reflejo cada vez. Para que puedas almacenar el resultado en caché:

public class DynamicForwarder : DynamicObject { private object _target; private Dictionary<string, object> _cache = new Dictionary<string, object>(); public DynamicForwarder(object target) { _target = target; } public override bool TryGetMember( GetMemberBinder binder, out object result) { // check the cache first if (_cache.TryGetValue(binder.Name, out result)) return true; var prop = _target.GetType().GetProperty(binder.Name); if (prop == null) { result = null; return false; } result = prop.GetValue(_target, null); _cache.Add(binder.Name, result); // <-------- insert into cache return true; } }

Podría admitir el almacenamiento de una lista de objetos de destino para unir sus propiedades y las propiedades de configuración de soporte (con una anulación similar llamada TrySetMember ) para permitirle establecer dinámicamente valores en el diccionario de caché.

Por supuesto, la sobrecarga de la reflexión probablemente no valdrá la pena preocuparse, pero para objetos grandes, esto podría limitar el impacto de la misma. Lo que tal vez sea más interesante es la flexibilidad adicional que te brinda.


Use Reflection.Emit para crear un método genérico para completar un ExpandoObject.

O use expresiones quizás (creo que esto solo sería posible en .NET 4).

Ninguno de estos enfoques usa la reflexión al invocar, solo durante la configuración de un delegado (que obviamente necesita ser almacenado en caché).

Aquí hay un código Reflection.Emit para llenar un diccionario (supongo que ExpandoObject no está lejos);

static T CreateDelegate<T>(this DynamicMethod dm) where T : class { return dm.CreateDelegate(typeof(T)) as T; } static Dictionary<Type, Func<object, Dictionary<string, object>>> cache = new Dictionary<Type, Func<object, Dictionary<string, object>>>(); static Dictionary<string, object> GetProperties(object o) { var t = o.GetType(); Func<object, Dictionary<string, object>> getter; if (!cache.TryGetValue(t, out getter)) { var rettype = typeof(Dictionary<string, object>); var dm = new DynamicMethod(t.Name + ":GetProperties", rettype, new Type[] { typeof(object) }, t); var ilgen = dm.GetILGenerator(); var instance = ilgen.DeclareLocal(t); var dict = ilgen.DeclareLocal(rettype); ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Castclass, t); ilgen.Emit(OpCodes.Stloc, instance); ilgen.Emit(OpCodes.Newobj, rettype.GetConstructor(Type.EmptyTypes)); ilgen.Emit(OpCodes.Stloc, dict); var add = rettype.GetMethod("Add"); foreach (var prop in t.GetProperties( BindingFlags.Instance | BindingFlags.Public)) { ilgen.Emit(OpCodes.Ldloc, dict); ilgen.Emit(OpCodes.Ldstr, prop.Name); ilgen.Emit(OpCodes.Ldloc, instance); ilgen.Emit(OpCodes.Ldfld, prop); ilgen.Emit(OpCodes.Castclass, typeof(object)); ilgen.Emit(OpCodes.Callvirt, add); } ilgen.Emit(OpCodes.Ldloc, dict); ilgen.Emit(OpCodes.Ret); cache[t] = getter = dm.CreateDelegate<Func<object, Dictionary<string, object>>>(); } return getter(o); }


tienes que usar la reflexión .... ( código "prestado" de esta URL )

using System.Reflection; // reflection namespace // get all public static properties of MyClass type PropertyInfo[] propertyInfos; propertyInfos = typeof(MyClass).GetProperties(BindingFlags.Public | BindingFlags.Static); // sort properties by name Array.Sort(propertyInfos, delegate(PropertyInfo propertyInfo1, PropertyInfo propertyInfo2) { return propertyInfo1.Name.CompareTo(propertyInfo2.Name); }); // write property names foreach (PropertyInfo propertyInfo in propertyInfos) { Console.WriteLine(propertyInfo.Name); }


foreach(var prop in myVar.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { Console.WriteLine("Name: {0}, Value: {1}",prop.Name, prop.GetValue(myVar,null)); }