martes, 28 de abril de 2015

Diferencias entre tipos de datos var y dynamic en C#

Tal vez has visto en ejemplos de código, en internet o incluso en el código de algún compañero en tu empresa que se declaran variables var o incluso dynamic, ¿cuál es la diferencia entre var y dynamic?.

Si tenemos que dividir los lenguajes de programación de acuerdo a los tipos de datos que manejan podríamos establecer 2 grandes categorías:

-Tipos de datos dinámicos: Los tipos de datos dinámicos no se verifican en tiempo de compilación y hacen la verificación del tipo de variable en tiempo de ejecución, por ejemplo JavaScript.
-Tipos de datos estáticos: Los tipos de datos estáticos son tipos de datos predefinidos (int, string, bool, struct) y la verificación del tipo de variable se realiza al compilar el código, por ejemplo Java y C#.

Veamos las características de var y dynamic.

var

Pueden declararse variables var en lugar de declararse como un tipo específico (por ejemplo int o string). El compilador infiere el tipo de variable; es decir, podemos declarar una variable como var llamada varEjemplo y asignarle un valor de "lambdaBox.blogspot.com", el compilador determinará que es un tipo de datos string, eso nos evita tener que declarar el tipo de datos en cada declaración de variables.

Nota: Es importante remarcar que var no es un tipo de dato, es más bien un auxiliar al momento de declarar variables.




var es muy utilizado en expresiones LINQ donde se obtienen tipos de datos anónimos (ya que se pueden llegar a generar tipos muy complejos).



En éste otro ejemplo he agregado la variable empleados a la ventana "watch" (click derecho "add watch") y podemos observar que el tipo de datos incluye el texto AnonymousType16. Cada vez que creamos un tipo de datos anónimo, el compilador determina si ya existe un tipo de datos anónimo con las mismas características y los agrupa como un mismo tipo de datos anónimo.


dynamic

Con la introducción del tipo de datos dynamic, podemos simular un entorno dinámico en un lenguaje estático (ya que internamente, las variables siguen siendo dynamic pero tenemos que declararlas con este tipo específico). La ventaja (y desventaja) del tipo de datos dynamic es que podemos cambiar el tipo de datos en tiempo de ejecución:


Una ventaja de utilizar dynamic es la capacidad de utilizar propiedades dinámicas en conjunto con la clase ExpandoObject, puedes encontrar información aquí.

Las diferencias

Con dynamic, el compilador no hace verificaciones de tipo de datos, por lo que podemos definir Métodos inexistentes y no tendremos errores de compilación, pero tendremos errores en tiempo de ejecución:






Sin embargo, si cambiamos esa misma declaración de dynamic a var, el compilador nos arroja un error al intentar compilar:



Un aspecto interesante es que podemos asignar un tipo dynamic a una declaración var. Recordemos que var no es un tipo de datos, únicamente le indica al compilador que asigne a la variable el tipo de datos correspondiente, en este ejemplo tenemos una variable dynamic de nombre objetoD y de tipo Object; posteriormente declaramos una variable (con var) llamada objetoVar y hacemos la asignación de objetoD (recordemos que objetoD es dynamic), por lo tanto el compilador asigna un tipo de dato dynamic a la variable objetoVar.


Les dejo el código utilizado como ejemplo (Visual Studio 2013):

namespace VarAndDynamicConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            /****   var ****/
            var varEjemplo = "lambdaBox";   //no es necesario declarar un string
            Console.WriteLine("Tipo de datos: " + varEjemplo.GetType());
            //Output->Tipo de datos: System.String
            varEjemplo += ".blogspot.com";
            Console.WriteLine("Valor: " + varEjemplo);
            //Output->Valor: lambdaBox.blogspot.com

            var varEjemploNum = 1;          //no es necesario declarar un int
            Console.WriteLine("Tipo de datos: " + varEjemploNum.GetType());
            //Output->Tipo de datos: System.Int32
            varEjemploNum += 1;
            Console.WriteLine("Valor: " + varEjemploNum);
            //Output->Valor: 2

            Console.WriteLine();

            /****   dynamic ****/
            dynamic dynamicEjemplo = "lambdaBox";
            Console.WriteLine("Tipo de datos: " + dynamicEjemplo.GetType());
            //Output->Tipo de datos: System.String
            dynamicEjemplo += ".blogspot.com";
            Console.WriteLine("Valor: " + dynamicEjemplo);
            //Output->Valor: lambdaBox.blogspot.com

            dynamicEjemplo = 1; //utilizamos la misma variable dynamic
            Console.WriteLine("Tipo de datos: " + dynamicEjemplo.GetType());
            //Output->Tipo de datos: System.Int32
            dynamicEjemplo += 1;
            Console.WriteLine("Valor: " + varEjemploNum);
            //Output->Valor: 2

            dynamic ejemplo2 = new Ejemplo();
            ejemplo2.Operacion1();
            //Output->Operacion1()
            //ejemplo2.OperacionNoExistente();    //<-Excepción


            dynamic objetoD = new Object();
            Console.WriteLine("Tipo de datos: " + objetoD.GetType());
            //Output->Tipo de datos: System.Object
            var objetoVar = objetoD;    //objetoD es dynamic
            Console.WriteLine("Tipo de datos: " + objetoVar.GetType());
            //Output->Tipo de datos: System.Object
            objetoVar = "lambdaBox";
            Console.WriteLine("Tipo de datos: " + objetoVar.GetType());
            //Output->Tipo de datos: System.String

            Console.ReadLine(); 
        }
    }

    public class Ejemplo
    {
        public void Operacion1()
        {
            System.Console.WriteLine("Operacion1()");
        }
    }
}