O Mads Torgersen apresenta mais detalhes sobre a palavra reservada dynamic no C# e como ela foi concebida. Incluso estão alguns designs alternativos que foram eventualmente descartados para dar lugar à palavra reservada dynamic.
O C# 4 suportará late binding (vinculação tardia) através do novo meta-tipo “dynamic”. Qualquer variável declarada diretamente ou retornada de uma função com este tipo será automaticamente tratada como vinculação tardia. Isto é parecido com as variáveis declaradas como “object” no Visual Basic, mas qualquer sistema de tipos será suportado e não apenas o CTS (common type specification) e o COM. will support any type system, not just CTS (common type specification) and COM.
Um ponto importante é que o objetivo desta funcionalidade é suportar vinculação tardia, mais recentemente chamada de dynamic binding (vinculação dinâmica). Tipagem dinâmica não é explicitamente uma funcionalidade da linguagem C#, mas sim uma conseqüência de ela suportar vinculação dinâmica.
É importante observar que reflection não é uma alternativa viável. O problema do reflection é que há muitas variações. A forma como você chama um método utilizando o namespace Reflection é diferente da forma como você chama um método em um ScriptObject. Além disso, métodos Ruby/Python têm um terceiro mecanismo.
Uma opção era fazer com que toda operação dinâmica tivesse um til (“~”) como prefixo. Infelizmente isso rapidamente sai do controle, especialmente ao se observar conversão de tipos, índices de matrizes e operadores matemáticos.
object d = GetDynamicObject(); string result = ~(string) d ~[ d~.Length ~- 1];
Outra opção considerada foi utilizar contextos dinâmicos. Assim como contextos unsafe e unchecked, você poderia demarcar um bloco de código arbitrário como “dynamic”. O problema com esta solução é que ficaria difícil misturar código estático com código dinâmico. Essa solução teria esse formato:
dynamic { //some dynamic code static { //some statically bound code dynamic { //some dynamic code in some static code } //some more statically bound code } //some more dynamic code }
A terceira solução era expressões contagiosas. Com isto, a natureza dinâmica de uma expressão seria propagada.
object d = GetDynamicObject(); string result = (string) d[ dynamic(d).Length - 1];
Claro que a sintaxe escolhida também não é perfeita. Apesar de facilitar a leitura do código, não há nada que indica que uma chamada dinâmica é feita no ponto de execução em questão. Essa informação está disponível apenas onde a variável é declarada.
dynamic d = GetDynamicObject(); string result = (string) d[d.Length - 1];
Um dos motivos principais que fez com que se aceitasse este modelo é que o código não fica, na prática, menos seguro. Fazer uma chamada dinâmica, por si só, tem as mesmas chances de lançar uma exceção quanto antes, mas dessa forma ganha-se o benefício de não ser necessário escrever um código bagunçado e passível de erros com lógica de reflection.
Outra opção considerada foi criar um modificador dynamic ao invés de uma meta-tipo. Com o modelo mostrado abaixo, os desenvolvedores poderiam fazer vinculação pré-matura nos métodos de Foo, mas fazer vinculação tardia em todo o resto. Enquanto isso poderia melhorar a performance em condições de contorno, adicionaria um nível de complexidade geral que não deixava ninguém satisfeito.
dynamic Foo d = GetDynamicFooObject();
Sempre que houver um componente dinâmico em uma expressão, a expressão toda provavelmente será dinâmica. Isso inclui:
- Chamada de métodos
- Invocações
- Acesso a membros
- Aplicação de operadores
- Indexação
As exceções são óbvias. Conversões e construtores te retornarão um contexto estático. Apesar de conversões poderem ser sobrescritas pelo sistema de tipos do DLR, o DLR obriga o resultado da conversão em um tipo apropriado.