tag see remarks method generate example documentacion cref comentarios c# reflection

remarks - see cref c#



cómo establecer el tipo que admite nulos a través del código de reflexión(c#)? (8)

Necesito establecer las propiedades de una clase usando reflexión.

Tengo un Dictionary<string,string> con nombres de propiedad y valores de cadena.

Dentro de un ciclo de reflexión, necesito convertir el valor de cadena al tipo de propiedad apropiado mientras establezco el valor para cada propiedad. Algunos de estos tipos de propiedades son tipos anulables.

  1. ¿Cómo puedo saber de PropertyInfo si la propiedad es un tipo anulable?
  2. ¿Cómo puedo establecer un tipo que admite nulos mediante la reflexión?

editar: el primer método definido en los comentarios en este blog parece ser el truco también: http://weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx


¿Por qué necesita saber si se puede anotar? ¿Y te refieres a "tipo de referencia", o " Nullable<T> "?

De cualquier manera, con valores de cadena, la opción más fácil sería a través del TypeConverter , que es más fácil (y más preciso) disponible en PropertyDescriptor :

PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj); // then per property... PropertyDescriptor prop = props[propName]; prop.SetValue(obj, prop.Converter.ConvertFromInvariantString(value));

Esto debería usar el convertidor correcto, incluso si se establece por propiedad (en lugar de por tipo). Finalmente, si está haciendo mucho de esto, esto permite la aceleración a través de HyperDescriptor , sin cambiar el código (que no sea habilitarlo para el tipo, hecho solo una vez).


He creado una pequeña muestra. Si tiene alguna pregunta sobre este código, agregue comentarios.

EDIT : muestra actualizada basada en el gran comentario de Marc Gravell

class Program { public int? NullableProperty { get; set; } static void Main(string[] args) { var value = "123"; var program = new Program(); var property = typeof(Program).GetProperty("NullableProperty"); var propertyDescriptors = TypeDescriptor.GetProperties(typeof(Program)); var propertyDescriptor = propertyDescriptors.Find("NullableProperty", false); var underlyingType = Nullable.GetUnderlyingType(propertyDescriptor.PropertyType); if (underlyingType != null) { var converter = propertyDescriptor.Converter; if (converter != null && converter.CanConvertFrom(typeof(string))) { var convertedValue = converter.ConvertFrom(value); property.SetValue(program, convertedValue, null); Console.WriteLine(program.NullableProperty); } } } }


La comprobación de los tipos Nullable es fácil, int? es realmente System.Nullable<System.Int32> . Entonces, simplemente verifica si el tipo es una instancia genérica de System.Nullable<T> . La configuración no debe marcar la diferencia, nullableProperty.SetValue(instance, null) o nullableProperty.SetValue(instance, 3)


  1. Una forma de hacer esto es:

    type.GetGenericTypeDefinition() == typeof(Nullable<>)

  2. Just set es como cualquier otro código de reflexión:

    propertyInfo.SetValue(yourObject, yourValue);


Originalmente, la mejor solución se menciona en el foro de MSDN . Sin embargo, cuando necesite implementar una solución dinámica, donde no sabe exactamente cuántos campos anulables se pueden declarar en una clase, lo mejor es comprobar si se puede asignar Nullable <> tipo a la propiedad, que se inspecciona a través de reflexión

protected T initializeMe<T>(T entity, Value value) { Type eType = entity.GetType(); foreach (PropertyInfo pi in eType.GetProperties()) { //get and nsame of the column in DataRow Type valueType = pi.GetType(); if (value != System.DBNull.Value ) { pi.SetValue(entity, value, null); } else if (valueType.IsGenericType && typeof(Nullable<>).IsAssignableFrom(valueType)) //checking if nullable can be assigned to proptety { pi.SetValue(entity, null, null); } else { System.Diagnostics.Trace.WriteLine("something here"); } ... } ... }


Específicamente para convertir un entero a una enumeración y asignar a una propiedad enum anulable:

int value = 4; if(propertyInfo.PropertyType.IsGenericType && Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null && Nullable.GetUnderlyingType(propertyInfo.PropertyType).IsEnum) { var enumType = Nullable.GetUnderlyingType(propertyInfo.PropertyType); var enumValue = Enum.ToObject(enumType, value); propertyInfo.SetValue(item, enumValue, null); //-- suggest by valamas //propertyInfo.SetValue(item, (value == null ? null : enumValue), null); }


aquí está la solución más segura para el tipo de objeto "nullable"

if (reader[rName] != DBNull.Value) { PropertyInfo pi = (PropertyInfo)d[rName.ToLower()]; if (pi.PropertyType.FullName.ToLower().Contains("nullable")) pi.SetValue(item, reader[rName]); else pi.SetValue(item, Convert.ChangeType(reader[rName], Type.GetType(pi.PropertyType.FullName)), null); }


He utilizado la siguiente solución, evitando el uso de convertidor de tipo para tener más control sobre el código.

Escribí una clase de ayuda para apoyar operaciones

using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Text; public static class ObjectExtensions { /// <summary> /// Enable using reflection for setting property value /// on every object giving property name and value. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="target"></param> /// <param name="propertyName"></param> /// <param name="value"></param> /// <returns></returns> public static bool SetProperty<T>(this T target, string propertyName, object value) { PropertyInfo pi = target.GetType().GetProperty(propertyName); if (pi == null) { Debug.Assert(false); return false; } try { // Convert the value to set to the properly type value = ConvertValue(pi.PropertyType, value); // Set the value with the correct type pi.SetValue(target, value, null); } catch (Exception ex) { Debug.Assert(false); return false; } return true; } private static object ConvertValue(Type propertyType, object value) { // Check each type You need to handle // In this way You have control on conversion operation, before assigning value if (propertyType == typeof(int) || propertyType == typeof(int?)) { int intValue; if (int.TryParse(value.ToString(), out intValue)) value = intValue; } else if (propertyType == typeof(byte) || propertyType == typeof(byte?)) { byte byteValue; if (byte.TryParse(value.ToString(), out byteValue)) value = byteValue; } else if (propertyType == typeof(string)) { value = value.ToString(); } else { // Extend Your own handled types Debug.Assert(false); } return value; } }

Nota. Cuando establece un valor que admite valores NULL (por ejemplo, int), el valor debe ser casi un entero o un tipo convertible. No puede establecer int en un byte. Por lo tanto, debe convertir correctamente. Consulte el código de ConvertValue (), que verificará para tipo (int) y tipo anulable correspondiente (int?))

Este es un código para establecer valores con la estructura de datos requerida, Diccionario.

public class Entity { public string Name { get; set; } public byte? Value { get; set; } } static void SetNullableWithReflection() { // Build array as requested Dictionary<string, string> props = new Dictionary<string, string>(); props.Add("Name", "First name"); props.Add("Value", "1"); // The entity Entity entity = new Entity(); // For each property to assign with a value foreach (var item in props) entity.SetProperty(item.Key, item.Value); // Check result Debug.Assert(entity.Name == "First name"); Debug.Assert(entity.Value == 1); }