Recientemente me encontré con un código que utilizando Reflection establecía valores a las propiedades de un objeto. El valor que iba a establecer en la propiedad tenía como tipo de dato String y la propiedad podía llegar a tener otro, entonces, utilizaba Convert.ChangeType cuando el tipo de dato de la propiedad era diferente a String:
class Persona { int _Edad; public int Edad { get { return _Edad; } set { _Edad = value; } } string _Nombre; public string Nombre { get { return _Nombre; } set { _Nombre = value; } } string _Apellido; public string Apellido { get { return _Apellido; } set { _Apellido = value; } } Nullable<int> _CantidadHijos; public Nullable<int> CantidadHijos { get { return _CantidadHijos; } set { _CantidadHijos = value; } } Nullable<int> _CantidadHermanos; public Nullable<int> CantidadHermanos { get { return _CantidadHermanos; } set { _CantidadHermanos = value; } } }
static void Main(string[] args) { StringDictionary lDiccionarioPropiedadesValores = new StringDictionary(); lDiccionarioPropiedadesValores.Add("Edad", "18"); lDiccionarioPropiedadesValores.Add("Nombre", "Nicolás"); lDiccionarioPropiedadesValores.Add("Apellido", "Ferreira"); lDiccionarioPropiedadesValores.Add("CantidadHijos", ""); lDiccionarioPropiedadesValores.Add("CantidadHermanos", "2"); Persona lPersona = new Persona(); foreach (DictionaryEntry lEntradaDiccionario in lDiccionarioPropiedadesValores) { PropertyInfo lPropiedadPersona = lPersona.GetType().GetProperty(lEntradaDiccionario.Key.ToString(), System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); if (lPropiedadPersona != null) { object lNuevoValorPropiedad = lEntradaDiccionario.Value; if ((lNuevoValorPropiedad != null) && (lPropiedadPersona.PropertyType != lEntradaDiccionario.Value.GetType())) { lNuevoValorPropiedad = Convert.ChangeType(lNuevoValorPropiedad, lPropiedadPersona.PropertyType); } lPropiedadPersona.SetValue(lPersona, lNuevoValorPropiedad, null); } } }
El problema al correr este código es que cuando la propiedad tiene como tipo de dato a Nullable, el método Convert.ChangeType falla. La solución puede ser la siguiente:
static void Main(string[] args) { StringDictionary lDiccionarioPropiedadesValores = new StringDictionary(); lDiccionarioPropiedadesValores.Add("Edad", "18"); lDiccionarioPropiedadesValores.Add("Nombre", "Nicolás"); lDiccionarioPropiedadesValores.Add("Apellido", "Ferreira"); lDiccionarioPropiedadesValores.Add("CantidadHijos", ""); lDiccionarioPropiedadesValores.Add("CantidadHermanos", "2"); Persona lPersona = new Persona(); foreach (DictionaryEntry lEntradaDiccionario in lDiccionarioPropiedadesValores) { PropertyInfo lPropiedadPersona = lPersona.GetType().GetProperty(lEntradaDiccionario.Key.ToString(), System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); if (lPropiedadPersona != null) { object lNuevoValorPropiedad = lEntradaDiccionario.Value; if ((lNuevoValorPropiedad != null) && (lPropiedadPersona.PropertyType != lEntradaDiccionario.Value.GetType())) { if ((lPropiedadPersona.PropertyType.IsGenericType) && (lPropiedadPersona.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))) { if (string.IsNullOrEmpty(lNuevoValorPropiedad.ToString())) { lNuevoValorPropiedad = null; } else { lNuevoValorPropiedad = Convert.ChangeType(lNuevoValorPropiedad, new NullableConverter(lPropiedadPersona.PropertyType).UnderlyingType); } } else { lNuevoValorPropiedad = Convert.ChangeType(lNuevoValorPropiedad, lPropiedadPersona.PropertyType); } } lPropiedadPersona.SetValue(lPersona, lNuevoValorPropiedad, null); } } }
El trabajo lo hace la clase NullableConverter, lo otro es simplemente validación.