[C#] Instancias en runtime de tipos dinámicos

 

Durante el desarrollo de algunas herramientas es necesario generalizarlas para poder reutilizarlas posteriormente, pero manteniendo siempre una funcionalidad concreta. En el caso que nos ocupa, quiero poder listar una serie de atributos genéricos y poder operar con ellos en la precisión deseada, pero partiendo de la premisa anterior. Es decir, no tendré una clase que disponga de algo similar:

  1. public class A
  2.         {
  3.             int a;
  4.             float b;
  5.             int c;
  6.             UInt16 x;
  7.         }

Esto es muy costoso de mantener en futuros proyectos, puesto que estaría obligado a cambiar manualmente todos los atributos del objeto y sus nombres pese a que el comportamiento puede estar definido, puesto que sólo me interesa poder operar con los números.

¿Solución? Pues muy sencillo. Por un lado, vamos a almacenar únicamente el  nombre de atributo junto con su tipo y valor, todo con string. Posteriormente usaremos reflection para cargar el tipo de forma dinámica. Hasta aquí todo es correcto, nuestro mayor problema será que el evidentemente esos objetos dinámicos no son tipados y el compilador no sabrá qué son salvo que lo especifiquemos explícitamente mediante un casting. Es por ello que aquí entran los tipos dinámicos.

Los tipos dinámicos (o dynamic type, en inglés) es una nueva feature de C# 4.0. Recomiendo la lectura de la documentación para no caer en el error de confundirlos con los tipos anónimos. Debemos tener en cuenta que lo que queremos es operar con ellos en tiempo de ejecución, por lo que toda operación no soportada en tiempo de compilación por un tipo no nos servirá. De ahí que los tipos anónimos no sirva para el siguiente ejemplo, ya que no puedo operar entre objetos sin especificar explícitamente qué quiero hacer.

Es por ello que una vez tenemos el tipo deseado a instanciar mediante Reflection, podemos asignarle el valor y el tipo a la variable dinámica. Y podremos operar con ellos como si se tratase de tipos compilados previamente. Veamos un ejemplo:

  1. class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             string uno = "1";
  6.             string dos = "2,5";
  7.  
  8.             dynamic a = Convert.ChangeType(uno, Type.GetType("System.Single"));
  9.             dynamic b = Convert.ChangeType(dos, Type.GetType("System.Single"));
  10.  
  11.             Console.Out.WriteLine(a);
  12.             Console.Out.WriteLine(b);
  13.             Console.Out.WriteLine(a+b);
  14.             Console.Out.WriteLine(a-b);
  15.             Console.Out.WriteLine(a*b);
  16.             Console.Out.WriteLine(a/b);
  17.             Console.ReadLine();
  18.         }
  19.     }

A través de Type.GetType() uso Reflection para cargar el tipo que quiero instanciar. Con Convert.ChangeType asigno un valor a un tipo, y todo ello a una variable dinámica. De este modo podremos operar con los números como si se tratasen de floats.

3 comentarios en “[C#] Instancias en runtime de tipos dinámicos”

  1. Muy buen post, directo y útil.
    Estoy diseñando una biblioteca -para una especie de gestor de contenido- y en principio en la base de datos, almaceno los tipos primitivos con su correspondiente en sql (hay una tabla valores). Me había planteado castearlos manualmente, pero aparte del trabajo que llevaría hacer eso, me preocupaba el espacio que ocuparía en memoria.
    ¿Valdrá la pena sacrificar memoria y hacer los tipos dinámicos, es decir, almacenar todos los datos como strings?

    Saludos y enhorabuena

  2. Gracias!
    Siempre puedes acotar en tu BD de cuánto quieres el tamaño de los campos, por lo que la memoria la puedes controlar. Por otra parte no me atrevo a decirte si merece la pena o no, porque depende de muchos casos. En el mío particular y en el caso en el que nació este post es que no sólo me importan los datos, sino que además me importan las operaciones que debo aplicar sobre ellos y más cosas. Y el modo más cómodo de hacerlo es con tipos dinámicos. También se puede hacer a la antigua usanza, pero lleva más trabajo como bien afirmas.
    Un saludo!

  3. Soy #1
    Sí, finalmente lo he hecho así, ya que al igual que en tu caso, lo que me interesa son las operaciones. Lo único que por lo que he estado viendo convert sólo funciona con tipos base. Pero bueno, por ahora sólo guardaré ese tipo de datos.

    Lo que estoy desarrollando se trata de una capa de abstracción por encima de EF, que permite desarrollar páginas webs de gestión (inmobiliarias, gestión de contenidos, etc.) relativamente rápido.

    Gracias y te animo a que sigas posteando artículos.

Deja un comentario

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