Fala filhotes, tudo bem? A pouco tempo atrás fiz um post sobre o Simple.Data, que usava o tipo Dynamic do .net 4.0. Como não tinha nenhum artigo aqui no 100loop vamos ao primeiro.

Funcionamento

O tipo dynamic permite que suas operações sejam resolvidas apenas em tempo de execução e não em tempo de compilação. Podendo acessar qualquer operação de qualquer tipo de objeto ( semelhante ao reflection) apenas invocando a operação.
– “Como assim?”
Vamos dizer que nossa classe Turma só tem uma propriedade Codigo. Se eu tentasse fazer isso:
Iria me mandar esse erro:

_100LoopProject.Classes.Turma’ does not contain a definition for ‘Nome’ and no extension method ‘Nome’ accepting a first argument of type ‘_100LoopProject.Classes.Turma’ could be found (are you missing a using directive or an assembly reference?) 

Afinal não existe essa propriedade. Mas se eu fizesse usando o dynamic:

dynamic turma = new Turma();
turma.Codigo = 1;
turma.Nome = "Turma 1";

Não daria erro nenhum, ja que o compilador “ignora” o dynamic, mas quando a aplicação executar essa linha e ver que “Nome” não existe, ai sim, vai gerar uma exceção. Entendeu? O dynamic funciona igual a um object mas suas operações não são resolvidas e nem conferidas pelo compilador.

Dynamic Language Runtime

O Dynamic Language Runtime (DLR) é uma nova API presente no framework 4.0 e adiciona uma série de serviços para linguagens dinâmicas ao CLR. É ela que permite o uso do tipo dynamic no C# e das linguagens dinâmicas como o IronPython e o IronRuby.

Arquitetura do DLR

A conversão do tipo dynamic em tempo de execução

Mas então, como minha aplicação vê esse tipo dynamic? Bom, na verdade é o seguinte: Quando o dynamic é compilado ele vira um object.

Wait, what?”

Um exemplo fica mais fácil de entender. Vou criar um objeto dynamic, setar diversos valores e verificar qual o seu tipo em tempo de execução:

// Criamos o nosso objeto Dynamic
dynamic objDyn;

objDyn = 3;
//Retona System.Int32
Console.WriteLine(objDyn.GetType());

objDyn = "andre";
//Retona System.String
Console.WriteLine(objDyn.GetType());

objDyn = new Usuario();
//Retona ProjetoTeste.ConsoleTest.Usuario
Console.WriteLine(objDyn.GetType());

Console.ReadLine();

Entedeu? Por isso pode se dizer que o Tipo dynamic só existe em tempo de compilação, ja que depois disso o próprio compilador analisa e grava as informações das operações alem de converter o cabloco dinamico para um tipo object.

Sim, filhotes. Com o reflection você consegue fazer tudo isso, mas com algumas diferenças, vamos la:

  // Pega o tipo do objeto
  var tp = typeof(Turma);
  // Cria uma instancia da turma
  var objTurma = Activator.CreateInstance(tp);
  // Usando Reflexion: Setando uma propriedade
  tp.GetProperty("Codigo").SetValue(objTurma, 1, null);
  // Chamo o método passando uma string como parametro
  tp.InvokeMember("GetDescription", BindingFlags.InvokeMethod, null, objTurma, new object[] { "Super turma de teste" });

E agora com o Dynamic:

// Pega o tipo do objeto
var tp = typeof(Turma);
// Cria uma instancia da turma
dynamic objTurma = Activator.CreateInstance(tp);
// Usando Dynamic: Setando uma propriedade
objTurma.Codigo = 1;
// Chamo o método passando uma string como parametro
objTurma.GetDescription("Super turma de teste");

Bang! 1×0 para o Dynamic

Então com o Dynamic nós os tratamos com o objetos normais, só chamamos o metodo/propriedade com seus valores/parâmetros e pronto! Bom, então o dynamic é mais facil, mas e a performace?
Opa mas é ai que as coisas mudam de figuras!… NOT!
Fazendo um programinha de testes:

 public static void Main(string[] args)
        {
            var nTimes = 1000000;
            var value = "Hello World";
            var myTestType = new MyTestType();
            DateTime start, end;

            var property = typeof(MyTestType).GetProperty("MyDynamicProperty");

            start = DateTime.Now;

            // Setando a propriedade via reflection
            for (var i = 0; i < nTimes; i++)
            {
                //var property = typeof(MyTestType).GetProperty("MyDynamicProperty");
                property.SetValue(myTestType, value, null);
            }

            end = DateTime.Now;

            Console.WriteLine(end.Subtract(start).ToString());
            dynamic myTestType2 = new MyTestType();
            start = DateTime.Now;
           // Setando a propriedade via dynamic
            for (int i = 0; i < nTimes; i++)
            {
                myTestType2.MyDynamicProperty = value;
            }

            end = DateTime.Now;

            Console.WriteLine(end.Subtract(start).ToString());

            // Setando a propriedade normalmente
            var myTestType3 = new MyTestType();

            start = DateTime.Now;
            for (int i = 0; i < nTimes; i++)
            {
                myTestType3.MyDynamicProperty = value;
            }

            end = DateTime.Now;

            Console.WriteLine(end.Subtract(start).ToString());
            Console.ReadLine();
        }
    }
    public class MyTestType
    {
        public string MyDynamicProperty { get; set; }
    }

Reflection: 00:00:01.7481000
Dynamic: 00:00:00.1080062
Normal: 00:00:00.0110006

Percebe-se que o Dynamic também é bem mais rapido do que o Reflection.
– “Nú! Então já posso migrar tudo para Dynamic!?”
Extamente! Não. Bom nem tudo nessa vida é tão simples assim...

Não existe nenhuma mágica


A maior vantagem do dynamic é também sua maior desvantagem. Lembra mais acima que eu falei que o compilador transforma ele em um tipo object? Então como ele pode acessar uma propriedade de um tipo desconhecido?
Usando reflection.

Mas perai se o dynamic tambem usa reflection porque ele é mais rapido?

Quando o compilador o transforma para um tipo object ele também cria um cache com as informações necessarias para acessar as propriedades de forma mais rapida. Qual a desvantagem disso? A primeira operação demora mais e perde um pouco da memória para manter o cache, tudo isso em troca de operações (bem) mais rapidas do que o reflection.

Conclusão

O dynamic é fantástico, mas como o reflection ele deve ser usado com cuidado, você não vai querer sobrecarregar o seu servidor atoa. E apesar de ter inumeras vantagens em cima do reflection analise bastante qual dos dois é melhor para sua aplicação, uma boa dica é dar uma olhada nesse tópico no Stack Overflow: http://stackoverflow.com/questions/4646786/dynamic-lang-runtime-vs-reflection.

Bom filhotes, então é isso pretendo fazer mais um post sobre dynamic semana que vem, ate mais.

Referências

http://lucisferre.net/2011/01/18/being-dynamically-typed-in-a-statically-typed-world/
http://www.codeproject.com/KB/cs/dynamicincsharp.aspx
http://www.amazedsaint.com/2010/03/c-40-dynamic-keyword-for-dummies-under.html
http://msdn.microsoft.com/en-us/library/dd264741.aspx
http://msdn.microsoft.com/en-us/library/dd264736.aspx
http://msdn.microsoft.com/en-us/library/dd233052.aspx
http://blog.wekeroad.com/2010/08/09/csharps-new-clothes
http://stackoverflow.com/questions/4646786/dynamic-lang-runtime-vs-reflection