De que se trata o artigo

O Dynamic Language Runtime (DLR) é uma implementação realizada no .net Framework que permite trabalhar com recursos de linguagem dinâmica. Dessa forma, podemos manipular objetos sem identificar o seu tipo, fazendo com que o mesmo aconteça em tempo de execução e não mais em tempo de design.


Em que situação o tema é útil

O desenvolvimento de funcionalidades que empreguem a tecnologia COM ou ainda, objetos gerados a partir de consultas LINQ pode, em inúmeras situações, exigir um esforço maior da parte dos desenvolvedores envolvidos em um projeto. Conversões de um tipo para outro e o acesso a informações via Reflection são práticas comuns em tais casos, sendo que a introdução do Dynamic Language Runtime a partir da versão 4.0 do .NET Framework procurou facilitar atividades deste gênero.

Dynamic Language Runtime - Manipulando objetos de uma forma mais flexível

Com o .NET Framework 4.0 foi introduzido o mecanismo conhecido como Dynamic Language Runtime (DLR). A utilização das diversas funcionalidades oferecidas pelo DLR acontece por meio da palavra-chave dynamic.

Veremos através deste artigo as vantagens e as preocupações no momento da utilização desse mecanismo e, ao final, desenvolveremos uma aplicação MVC de exemplo.

Considerando o comportamento no que diz respeito ao processo de compilação de instruções, as linguagens de programação podem ser divididas em dois grandes grupos: estáticas e dinâmicas. O critério básico para se efetuar esta classificação leva em conta em que momento as checagens envolvendo membros de um objeto (propriedades e métodos, por exemplo) são realizadas, assim como a identificação e validação dos tipos correspondentes a tais elementos.

C# e Java eram dois casos de linguagens que se caracterizam por um comportamento estático, ao passo que PHP, Python, Ruby e JavaScript são exemplos notórios de adoção de estruturas de programação com um aspecto dinâmico. Com o advento do Dynamic Language Runtime (DLR) o C# deixou de ser uma linguagem exclusivamente estática.

O Dynamic Language Runtime representa, em termos gerais, o mecanismo que torna possível a utilização de declarações dinâmicas em implementações baseadas na plataforma .NET. Foi a criação deste ambiente que permitiu, inclusive, o surgimento de linguagens puramente dinâmicas e baseadas no .NET Framework, como IronPython e IronRuby.

Do ponto de vista arquitetural, o DLR é composto por um conjunto de recursos que estendem as capacidades do Common Language Runtime (Nota DevMan 1), a fim de que este último consiga suportar objetos e tipos dinâmicos, são eles:

· Expression trees: Expression tree é a representação em memória de uma expressão lambda (Nota DevMan 2). Com este tipo de construção torna-se possível a manipulação dos diversos itens (nodes) que constituam essas expressões, visando com isto interpretar e processar o que foi informado nas mesmas para a produção de um resultado dentro de um padrão esperado. Trata-se de um mecanismo originalmente de LINQ a possibilitar a manipulação de instruções de controle de fluxo, associação de valores a variáveis e outros tipos de construções de código;

· Dynamic Call Site: o DLR faz uso de uma área de cache chamada “dynamic call site”. Trata-se de um local em que, logo após a primeira execução de uma instrução, são armazenadas informações sobre tipos dinâmicos; esta atividade busca tornar mais rápido o processamento posterior de instruções de código similares por parte do Dynamic Language Runtime;

· Binders: as chamadas via DLR à recursos do próprio .NET Framework, ao Silverlight ou, até mesmo, a componentes COM (envolvendo a interação com aplicativos do pacote Office, por exemplo) acontece através de elementos conhecidos como binders. Um binder representa, basicamente, um tipo de estrutura que encapsula todas as operações necessárias para a manipulação de recursos associados a objetos dinâmicos.

Nota do DevMan 1

O Common Language Runtime (CLR) corresponde à máquina virtual, através da qual é possível a execução de programas dentro da plataforma .NET. Entre as atividades desempenhadas por essa estrutura estão o gerenciamento de memória, garbage collection e controle de processos em paralelo (threads).

Nota do DevMan 2

Lambda expression é um tipo de função anônima, ou seja, uma estrutura que conta com um corpo (formado por uma ou mais expressões), mas que não apresenta um nome e uma organização similar à de métodos convencionais. Trata-se de um recurso bastante utilizado como meio para a passagem de parâmetros a outras operações, sem que seja necessária a escrita de construções num formato condicional. Normalmente uma lambda expression é formada por uma instrução curta e, em muitos casos, não excedendo uma linha de código, fato este que representa uma interessante vantagem ao evitar que numerosas funções simples precisem ser implementadas ao longo de uma classe.

A manipulação de objetos de uma maneira dinâmica em C# é feita basicamente por meio de declarações de variáveis empregando a palavra-chave dynamic. A utilização desta instrução é similar à de construções que utilizam o tipo object ou ainda, a palavra-chave var. No entanto, a definição de variáveis via palavra-chave dynamic fará com que a validação de operações só que aconteça em tempo de execução.

Diferenças entre VAR, OBJECT e DYNAMIC

Na Listagem 1 é apresentado um primeiro exemplo de declaração de uma variável dinâmica. Uma referência de nome “variavelExemplo” foi criada, atribuindo-se à mesma a data/hora atuais no computador em que esta instrução for executada. Muito embora as propriedades Day, Month e Year realmente pertençam ao objeto que foi vinculado a “variavelExemplo”, o compilador não executará nenhuma checagem determinando se estes elementos existem ou ainda, acerca do tipo dos mesmos (tentando impedir com isto a atribuição de um valor inválido a uma variável). Conforme já mencionado anteriormente, esta ação será disparada apenas em tempo de execução.

Listagem 1. Criando uma variável com a palavra-chave dynamic

...
   
  dynamic variavelExemplo = DateTime.Now;
   
  // Outras instruções
   
  ...
   
   
  // Acessando propriedades da instância dinâmica
   
  int dia = variavelExemplo.Day;
  int mes = variavelExemplo.Month;
  int ano = variavelExemplo.Year;
   
  ...

A Listagem 2 retoma o exemplo anterior, porém, neste novo trecho de código está a instrução que invoca a operação “AcessandoMetodoInvalido”: Este método não faz parte do tipo DateTime. Contudo, isto não implica, necessariamente, que um erro alertando acerca deste problema será gerado pelo compilador dentro de uma IDE como o Visual Studio. Na verdade, ocorrerá uma exceção em tempo de compilação dinâmica, haja visto o fato deste tipo de checagem ser realizado de maneira dinâmica através do mecanismo de runtime do .NET Framework (o que impede tal verificação em tempo de projeto).

Listagem 2. Acessando um método inválido para um objeto vinculado a uma variável dinâmica

...
   
  dynamic variavelExemplo = DateTime.Now;
   
  // Outras instruções
   
  ...
   
   
  // Acessando propriedades da instância dinâmica
   
  int dia = variavelExemplo.Day;
  int mes = variavelExemplo.Month;
  int ano = variavelExemplo.Year;
   
  ...
   
   
  // Erro ao se acessar um método que não existe
  // na definição do tipo DateTime
  variavelExemplo.AcessandoMetodoInvalido();
   
  ... 

A Listagem 3 demonstra uma implementação equivalente ao exemplo inicial, porém empregando desta vez uma variável (também chamada “variavelExemplo) cujo tipo é object. Novamente foi atribuído um valor representando a data e hora atuais à referência gerada, sendo que a utilização posterior da instância contida em “variavelExemplo” exigirá que se realize uma conversão (“type cast”) do tipo object para DateTime (algo que não acontece ao se fazer uso da palavra-chave dynamic). Além disso, a tentativa de se acessar uma propriedade ou método inexistente no tipo DateTime produzirá um erro de compilação, visto que a verificação em tempo de compilação encontra-se ativada neste segundo caso.

Listagem 3. Manipulando uma variável declarada com a palavra-chave object

...
   
  object variavelExemplo = DateTime.Now;
   
  // Outras instruções
   
  ...
   
              
  // Efetuando typecast para acessar propriedades
  int dia = ((DateTime)variavelExemplo).Day;
  int mes = ((DateTime)variavelExemplo).Month;
  int ano = ((DateTime)variavelExemplo).Year; 
   
  ... 

Na Listagem 4 está um exemplo de utilização da palavra-chave “var”. Uma instrução deste tipo tem o mesmo efeito de se declarar uma variável indicando explicitamente o tipo a ser empregado (no caso DateTime). O acesso a propriedades e operações do objeto gerado ocorre sem a necessidade de um “type cast”, sendo que isto é possível graças a um conceito conhecido como inferência de tipos (Nota DevMan 3).

Verificações típicas de linguagens estáticas ainda se encontram ativas aqui, ou seja, erros de compilação serão gerados mediante qualquer tentativa de se efetuar uma operação inválida no código (atribuição de um valor incompatível ou, mesmo, o acesso a um membro inválido da classe a qual variável “variavelExemplo” se refere).

Nota do DevMan 3

Inferência de tipos é uma técnica em que a partir de uma declaração genérica (via instrução "var"), uma variável é definida sem que seja obrigatório especificar de forma explícita o tipo do objeto ao qual a mesma se refere. Este é um recurso bastante utilizado com expressões que envolvam o uso de LINQ, sendo que o compilador da plataforma .NET é capaz de determinar sem maiores dificuldades, ao longo de uma série de instruções, a classe que serviu de base para a geração do objeto armazenado na variável em questão. Importante ressaltar, ao se considerar o ambiente de desenvolvimento do Visual Studio, que o IntelliSense também suporta construções que utilizem inferência de tipos.

Listagem 4. Manipulando uma variável declarada com a palavra-chave var

...
   
  var variavelExemplo = DateTime.Now;
   
  // Outras instruções
   
  ...
   
   
  // Acessando propriedades da instância associada à variável
   
  int dia = variavelExemplo.Day;
  int mes = variavelExemplo.Month;
  int ano = variavelExemplo.Year;
   
  ...  ... 

Quer ler esse conteúdo completo? Tenha acesso completo