una propiedades propiedad parametros metodos implementar entre diferencia con clase campo autoimplementadas agregar c# reflection getproperty

parametros - propiedades autoimplementadas c#



La mejor forma de obtener sub propiedades usando GetProperty (5)

Las respuestas existentes están bien; solo una perspectiva alternativa: en muchos escenarios, es deseable usar System.ComponentModel en lugar de reflexión directa, ya que esto permite escenarios de propiedades en tiempo de ejecución, es decir, cómo un DataView de DataTable expone las columnas como propiedades .

En lo que respecta al rendimiento: por defecto, esto es básicamente idéntico, pero si está haciendo mucho de esto (por ejemplo, importación / exportación masiva de datos), puede obtener aumentos de rendimiento significativos utilizando este enfoque, cortesía de HyperDescriptor .

Para usar System.ComponentModel, el código es similar, pero sutilmente diferente:

static void Main() { object obj = new Customer { Address = new Address { ZipCode = "abcdef" } }; object address = GetValue(obj, "Address"); object zip = GetValue(address, "ZipCode"); Console.WriteLine(zip); } static object GetValue(object component, string propertyName) { return TypeDescriptor.GetProperties(component)[propertyName].GetValue(component); }

Esto le da el mismo manejo que si hubiera utilizado el enlace de datos para enlazar a "Address.ZipCode" (pasando por alto algunos detalles como listas, etc.).

(Tenga en cuenta que podría lanzar zip como una cadena, etc., si sabe que es el tipo esperado)

Para obtener el valor de una ruta profunda (incluyendo el mismo manejo de listas que usa el enlace de datos), usaría algo como:

static object ResolveValue(object component, string path) { foreach(string segment in path.Split(''.'')) { if (component == null) return null; if(component is IListSource) { component = ((IListSource)component).GetList(); } if (component is IList) { component = ((IList)component)[0]; } component = GetValue(component, segment); } return component; }

El material de la lista refleja aproximadamente el comportamiento del enlace de datos normal (aunque omite algunas cosas como contextos vinculantes, gestores de divisas, etc.)

public class Address { public string ZipCode {get; set;} } public class Customer { public Address Address {get; set;} }

¿cómo puedo acceder a eitther "ZipCode" o "Address.ZipCode" con la reflexión? Por ejemplo:

Typeof(Customer).GetProperty("ZipCode")?


typeof (Customer).GetProperty("Address").PropertyType.GetProperty("ZipCode")


Necesitarías algo como:

PropertyInfo addressProperty = typeof(Customer).GetProperty("Address"); ProportyInfo zipCodeProperty = addressProperty.PropertyType.GetProperty("ZipCode"); object address = addressProperty.GetValue(customer, null); object zipCode = zipCodeProperty.GetValue(address, null);

Básicamente, si desea tomar una cadena "Address.ZipCode" y navegar hacia abajo, debe dividirla por "." y luego llame a GetProperty en el tipo apropiado en cada paso para obtener la propiedad en sí, luego PropertyInfo.GetValue para obtener el siguiente valor en la cadena. Algo como esto:

public static object FollowPropertyPath(object value, string path) { Type currentType = value.GetType(); foreach (string propertyName in path.Split(''.'')) { PropertyInfo property = currentType.GetProperty(propertyName); value = property.GetValue(value, null); currentType = property.PropertyType; } return value; }

Llámalo así:

object zipCode = FollowPropertyPath(customer, "Address.ZipCode");

Tenga en cuenta que esto funciona en los tipos de tiempo de compilación de las propiedades. Si desea que se adapte al tipo de tiempo de ejecución (por ejemplo, si customer.Address no tenía una propiedad ZipCode, pero sí el tipo devuelto por Address), entonces cambie property.PropertyType a property.GetType() .

También tenga en cuenta que esto no tiene ningún error de manejo, etc. :)


adabyron,

Creé una versión de tu código para cuando solo necesitas obtener los tipos, y si no tienes una instancia de objeto real.

public static Type FollowPropertyPath<T>(string path) { if (path == null) throw new ArgumentNullException("path"); Type currentType = typeof(T); foreach (string propertyName in path.Split(''.'')) { int brackStart = propertyName.IndexOf("["); var property = currentType.GetProperty(brackStart > 0 ? propertyName.Substring(0, brackStart) : propertyName); if (property == null) return null; currentType = property.PropertyType; if (brackStart > 0) { foreach (Type iType in currentType.GetInterfaces()) { if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof (IDictionary<,>)) { currentType = iType.GetGenericArguments()[1]; break; } if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof (ICollection<>)) { currentType = iType.GetGenericArguments()[0]; break; } } } } return currentType; }


La respuesta de Jon Skeet está bien, aunque tuve que extender un poco su método para dar cuenta de las instancias derivadas dentro de la ruta de la propiedad:

public static class ReflectorUtil { public static object FollowPropertyPath(object value, string path) { if (value == null) throw new ArgumentNullException("value"); if (path == null) throw new ArgumentNullException("path"); Type currentType = value.GetType(); object obj = value; foreach (string propertyName in path.Split(''.'')) { if (currentType != null) { PropertyInfo property = null; int brackStart = propertyName.IndexOf("["); int brackEnd = propertyName.IndexOf("]"); property = currentType.GetProperty(brackStart > 0 ? propertyName.Substring(0, brackStart) : propertyName); obj = property.GetValue(obj, null); if (brackStart > 0) { string index = propertyName.Substring(brackStart + 1, brackEnd - brackStart - 1); foreach (Type iType in obj.GetType().GetInterfaces()) { if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IDictionary<,>)) { obj = typeof(ReflectorUtil).GetMethod("GetDictionaryElement") .MakeGenericMethod(iType.GetGenericArguments()) .Invoke(null, new object[] { obj, index }); break; } if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IList<>)) { obj = typeof(ReflectorUtil).GetMethod("GetListElement") .MakeGenericMethod(iType.GetGenericArguments()) .Invoke(null, new object[] { obj, index }); break; } } } currentType = obj != null ? obj.GetType() : null; //property.PropertyType; } else return null; } return obj; } public static TValue GetDictionaryElement<TKey, TValue>(IDictionary<TKey, TValue> dict, object index) { TKey key = (TKey)Convert.ChangeType(index, typeof(TKey), null); return dict[key]; } public static T GetListElement<T>(IList<T> list, object index) { return list[Convert.ToInt32(index)]; } }

Usando property.PropertyType obtendrá el tipo de propiedad definido en la clase obj, mientras usa obj.GetType () obtendrá el tipo real de la instancia de la propiedad.

EDITAR: @Oliver: tienes toda la razón, gracias por notar eso. Ajusté el método para permitir listas y diccionarios genéricos. Aunque no me gusta la parte de análisis, utilicé la ingeniosa idea de Marc Gravell en este hilo para obtener los valores de la propiedad del indexador.