Pesquisar

13 de mar de 2008

Chamar métodos static por tipo variável é ilegal - Parte II

Na primeira parte vimos que os métodos static não sempre determinados em tempo de compilação, e usamos este fato para justificar o porque dos métodos static não poderem ser chamados em tipos passados por parâmetro. Mas os argumentos de tipos das Generics não são determinados em tempo de compilação?

No lado de quem os chama, sim. Mas para quem é chamado, o código enviado em tempo de compilação para um método genérico é inteiramente genérico. E assim continuará até que o jitter encontre o código em tempo de execução e faça a substituição dos tipos por argumento pelos tipos passados por parâmetros.

Considere a seguinte Generic:

public class C<T> { public string M() { return typeof(T).ToString(); } }


Quando você a compila, o compilador enviará uma definição de classe genérica que diz apenas que nós temos uma classe, que tem um tipo por parâmetro, e um método que chama o ToString(). Este é todo o código que é enviado para esta classe em tempo de compilação.

Para deixar mais claro, quando você diz:

void N() { C<int> c = new C<int>(); string s = c.M(); //...


O compilador não cria uma cópia da classe no código IL com o T substituído por int.

Em vez disso, o que acontece é que quando seu método N é jittado, o jitter diz, Hey, Eu preciso traduzir C<int>.M. Neste ponto o jitter consome o IL genérico emitido pelo C<T>.M e cria um novo código x86 (ou o que for) com int substituindo T.

Diferentemente dos templates no C++  que não definem tipos genéricos. Em vez disso, templates C++ são basicamente um atalho em tempo de compilação, como um complexo buscar-e-substituir. Se você dizer C<int> no C++, então em tempo de compilação, o compilador C++ textualmente irá substituir int pelo T e enviar o código como se você tivesse escrito a classe usando o int. 

Se o C# tivesse templates em vez de macros então um método static chamado em um template realmente seria determinado em tempo de compilação, porque a classe inteira seria processada em tempo de compilação. Este sentido de templates é um mecanismo  mais poderoso que generics – você pode fazer coisas loucas com templates porque eles não são "type safety" imposto sobre o modelo como um todo. Pelo contrário, o "type safety" só está marcado para cada construção do template efetivamente no programa.

Mas tipos genéricos no C# não são templates, eles devem ser "typesafe" dada qualquer possível construção a qual satisfaça as regras, não somente sobre um conjunto que está atualmente construído em um programa em particular. 

Nenhum comentário: