Outro dia estava conversando com um amigo sobre as mudanças que o .Net vem sofrendo com o passar dos anos. Uma das coisas que ele me questionou foi: “var veio pra substituir o Object…e agora o Dynamic veio pra substituir o var?”. Bem, vamos ver o que realmente são cada um destes tipos.

Como todos sabem, Object é a classe base na plataforma .net, System.Object, ou seja, muitos dos tipos que conhecemos tem sua descendência de Object mesmo isso não sendo explicitado. Sendo assim elas passam a herdar seus comportamentos e suas propriedades, como por exemplo Equals(Object obj), ToString() , GetHashCode() dentre outros.

Atento para a informação de que quando falamos que “tudo herda de Object” estamos sendo equivocados. Caso queiram ler mais sobre o assunto sugiro o post do Eric Lippert.

Com isso, quando criamos uma variável do tipo Object ela tem a capacidade de receber qualquer valor. Vamos ver um exemplo.

Listagem 01

String str = "Luciano"; // declaração do tipo String
Object obj = str;       // boxing
String s = (String)obj; // unboxing


Observem que defini a string “Luciano” à variável str que é do tipo String. Criei uma nova variável só que desta vez do tipo Object e informei que ela receberia o conteúdo da variável str, conhecemos isso como Boxing. Criei uma nova variável o tipo String, como havia dito antes, como todos os tipos derivam de System.Object, o tipo String poderá receber o valor da variável obj, pois foi atribuído a ela uma string. Porém precisamos realizar um “cast” que é uma conversão de tipos, pois como Object aceita qualquer coisa precisamos informar que ao passar o conteúdo de obj para outra variável de outro tipo teremos que informar pra qual tipo ela irá se “converter”. Conhecemos isso como Unboxing.

Vamos ver agora o tipo var

Primeiramente, só variáveis podem ser declaradas como sendo do tipo var. Bem, se eu declarar uma variável assim, quando eu for utilizar ela, ela poderá ter qualquer valor? Não. Isso porque o compilador não deixa você declarar uma variável somente com var sem fazer uma atribuição logo na declaração, pois é através dessa atribuição que ele vai inferir o tipo da variável, ou seja, sempre que você for utilizá-la ela terá um tipo já atribuído.

O conceito var pode nos remeter a pensar que estamos regredindo e deixando com que a linguagem se torne não tipada, que será uma coisa ruim, porém não é bem assim. Vamos ver realmente uma aplicação para o conceito de var.

Listagem 02

var objVariante = new
{
    Nome = "Luciano",
    Email = "teste@teste.com.br",
    CPF = 0123456789
};


Basicamente são tipos definidos de maneira dinâmica, sem necessitar de um tipo explicito previamente definido. Observe a figura 01

objvardyn_01

Figura 01 – Criação de um tipo Anonymous

Com esta construção armazenamos duas propriedades somente leitura em um tipo anônimo representado pela variável objVariante. Um detalhe importante sobre os anonymous types é que eles não são tipos genéricos e não causam boxing e unboxing de uma maneira oculta, eles são realmente objetos fortemente tipados, a diferença é que o compilador gera a implementação para nós onde lhe for conveniente.

As aplicações para o var são muitas, porém as que realmente fazem sentido são as aplicadas a LINQ.

E finalmente dynamic

O conceito de dynamic  muda um pouco do conceito que conhecemos até o momento, pois trás o poder das linguagens dinâmicas e mescla vantagens e desvantagens com a linguagem estática que é o C#. O dynamic não se restringe somente a variáveis, ele pode ser aplicado a propriedades, retorno de métodos, parâmetros, praticamente tudo. Quando você declara utilizando o dynamic está dizendo para o compilador que o objeto ali contido é desconhecido e que todas as operações efetuadas envolvendo este objeto só serão checadas em tempo de execução ( runtime ), sendo assim é possível invocar um método inexistente sem que o compilador dê erro, quando acontecer a chamada desse método é que o acontecerá verificação desse método, checagem de parâmetros e tudo mais, se algum problema for identificado durante a verificação ocorrerá uma exceção. Com esse recurso infelizmente perdemos qualquer ajuda da IDE em relação ao intellisense, pois o conceito do dinamismo impede que saibamos sobre informações do objeto de forma prévia.

Veja um exemplo na figura 02

objvardyn_02

Figura 02 – Declaração de um objeto do tipo Dynamic

Reparem que não existe intellisense, apenas uma informação da IDE dizendo que a chamada ao método Do() será resolvida em tempo de execução. Mas se perdemos em parte com isso qual a utilidade de se usar dynamic?

Umas das grandes vantagens é a utilização de Reflection e COM Interop. Veja um exemplo.

Listagem 03

dynamic inteiro = Activator.CreateInstance( Type.GetType( "System.Int32" ) );
Console.Write( inteiro ); // Irá imprimir 0 no console

dynamic data = Activator.CreateInstance( Type.GetType( "system.DateTime" ) );
Console.Write( data ); // Imprimirá 01/01/0001

Além disso, permite a interação com linguagens dinâmicas como IronPhyton e IronRuby, possiblidade de consumir e executar códigos escritos em IronPhyton e IronRuby dentro do C#.
 
Como puderam observar, todos três tipos possuem características próprias e cada um irá executar uma função diferente dentro da programação, sendo assim, nenhuma delas veio para substituir a outra, mas sim para agregar valores à linguagem C#.