Cómo convertir clases en diccionarios clave/valor

Cuestiones enviadas por lectoresEl otro día, a raíz del post Atajo para instanciar tipos anónimos en C# y VB.NET, el amigo Leo H., desde Argentina, me envió una cuestión:


[…] Me parece muy interesante crear diccionarios utilizando tipos anónimos, pues simplifica de una forma considerable la cantidad de código que hay que escribir para conseguir llenar una estructura de este tipo. De hecho, estoy pensando en utilizar esta técnica en una librería que estoy desarrollando, pero no veo claro cómo transformar después ese objeto anónimo en el diccionario equivalente […]


Verás que la idea es muy simple. Sólo necesitamos encontrar una fórmula que nos permita recorrer las propiedades del objeto, y por cada una de ellas, añadir la entrada correspondiente en el diccionario, especificando como clave el nombre de la propiedad y como valor el que tenga establecido la misma.

Una posibilidad muy sencilla es usar la clase TypeDescriptor, cuyo método GetProperties() nos devuelve una colección con los descriptores de las propiedades de la instancia que le pasemos como parámetro. Iterando sobre este conjunto, podremos ir llenando el diccionario con los elementos que nos interese, tal que así, dado un objeto llamado obj:

  Dictionary<string, object> dicc = new Dictionary<string, object>();
foreach (PropertyDescriptor desc in TypeDescriptor.GetProperties(obj))
{
dicc.Add(desc.Name, desc.GetValue(obj));
}


Pero vamos a dar una vuelta de tuerca más. Partiendo del código anterior, es muy fácil crear un método de extensión sobre la clase object, de forma que podamos convertir en un diccionario cualquier objeto de nuestras aplicaciones, con toda la potencia y comodidad que nos aporta esta técnica.

El código sería:

  public static class Extensions
{
public static Dictionary<string, object> ToDictionary(this object obj)
{
Dictionary<string, object> dicc = new Dictionary<string, object>();
foreach (PropertyDescriptor desc in TypeDescriptor.GetProperties(obj))
{
dicc.Add(desc.Name, desc.GetValue(obj));
}
return dicc;
}
}


De esta forma, dispondremos de una potente forma de «diccionarizar» nuestras instancias, sean del tipo que sean, por ejemplo:


var juan = new { nombre = «Juan», edad = 23 };
Dictionary<string, object> dicc = juan.ToDictionary();
Console.WriteLine(dicc[«nombre»]); // Escribe «Juan»

var dicc2 = «hola».ToDictionary();
Console.WriteLine(dicc2[«Length»]); // Escribe 4


Espero que te sea de ayuda, Leo. ¡Y gracias por participar en Variable Not Found!

Publicado en: www.variablenotfound.com.

5 comentarios sobre “Cómo convertir clases en diccionarios clave/valor”

  1. Hola, Jose!

    Ahí va mi opinión, a expensas de montar una discusión…

    Sin duda alguna, un truco muy interesante, pero que pienso habría que utilizar solo en los casos en que ello se justifique (aplicaciones que utilicen metaprogramación, por ejemplo). Decir que esta técnica es de aplicación universal equivaldría a negar el valor del strong typing.

    Creo que este podría ser un ejemplo típico de técnicas que mal utilizadas (por ejemplo, en manos de principiantes) pueden ser una verdadera bomba de relojería. Y esto solo lo digo en términos de «hacer las cosas bien» (lo que yo pienso que es «hacer las cosas bien», claro :-), sin tener en cuenta el rendimiento. Pero sustituir cada acceso a miembro por una búsqueda en un diccionario tendrá sin duda alguna un fuerte efecto negativo sobre el rendimiento.

    Salu2 – Octavio

  2. Jose,

    Por otra parte, no veo cuál es la dificultad de la que habla Leo para inicializar un diccionario. Bastaría con esto:

    var dict = new Dictionary
    {
    { «Nombre», «pepe» },
    { «Edad», 35 }
    };

    Slds – Octavio

  3. Hola, gracias por comentar.

    @Julio, para eso que comentas puede usar Reflection. Dado un objeto «obj» cualquiera, puedes obtener una enumeración de sus métodos llamando a obj.GetType().GetMethods(). Por cada elemento obtenido (del tipo MethodInfo) puedes leer su tipo de retorno, parámetros, etc., de forma muy sencilla.

    @Octavio, tienes toda la razón; el uso indebido de esta técnica rompe todas las reglas del tipado fuerte, y anula sus ventajas. Sin embargo, en casos como el que comentas o en entornos controlados, hay que reconocer que puede resultar muy cómodo.

    Por ejemplo, en ASP.NET MVC lo están utilizando como una vía rápida para especificar atributos de etiquetas HTML.

    Por ejemplo, la llamada:

    <%= Html.TextBox(«age», 23, new { MaxLength=3, Style=’color: red;’ }) %>

    genera en la página un código HTML como el siguiente:

    <input id=»age» name=»age» value=»23″ type=»text» maxlength=»3″ style=’color: red;’ />

    Se puede observar que en el tercer parámetro del método se indican las propiedades, todas opcionales, que serán renderizadas como atributos de la etiqueta INPUT, tal y como hayan sido escritas. No se tienen en cuenta tipos, ni nombres, ni nada parecido, sólo se usa para recopilar de forma rápida los atributos a añadir a la etiqueta.

    De hecho, hay otra sobrecarga del mismo método permite la especificación de las propiedades dentro de un Dictionary<string, object>, pero su utilización directa como parámetro de llamada al método es más farragosa, siendo igual de «poco tipada»:

    <%= Html.TextBox(«age», 23, new Dictionary<string,object>() { {«MaxLength», 3}, {«Style», «color: red» }} ) %>

    En fin, lo que le decía tío Ben a Peter Parker: «un gran poder conlleva una gran responsabilidad». 😉

    Saludos.

  4. Jose,

    Efectivamente, la programación web es uno de los mejores ejemplos de área en la que este estilo es muy útil. Se dice que Rails fue el que puso a Ruby en el mapa…

    Salu2 – Octavio

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *