Convert.ChangeType (Nullable<>)

by Nicolás Ferreira 13. January 2008 00:00

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.

Tags:

.NET Development