Qual é a performance atingida com a redução?
Pergunta
Apenas tentando entender os genéricos lendo Este artigo esclarecedor de Juval Lowy
Parafraseando .. Quando você define uma definição de classe genérica, ela é compilada em IL.
- Para tipos de valor, assim que você solicitar um tipo de valor específico, ele substitui o T pelo seu tipo de valor específico para obter o IL para essa configuração específica, por exemplo,
MyList<int>
Benefício: sem penalidades de boxe e unboxing. - Tudo de bom .. Para tipos de referência, o compilador substitui todas as instâncias de t em sua definição pelo objeto e cria o IL que é usado para todos os tipos de ref. As instâncias, no entanto, são alocadas com base no tipo de referência solicitado, por exemplo,
MyList<String>
Agora pré-generica, poderíamos ter métodos escritos que tomem Object
parâmetros. A melhoria de desempenho de reivindicações genéricas porque 'Evita a penalidade de desempenho que você incorre quando você abriu o tipo de objeto para o seu tipo específico quando quiser usá -lo '
// assume GetItem returns an Object
string sMyPreciousString = (string) obList.GetItem();
O que esse desempenho atingiu quando você abriu do tipo de referência específico? Além disso, parece que se destacar (mesmo os genéricos faria isso) não é um sucesso de desempenho. Por quê?
Solução
O upcasting para objeto não requer uma verificação de tempo de execução - sempre funcionará e é apenas um não -operatório basicamente.
A abaixação requer uma verificação de tempo de execução para garantir que você não esteja lançando um fluxo em uma string, por exemplo. É uma penalidade muito pequena e muito improvável de ser um gargalo - mas evitá -lo é apenas um benefício extra para os genéricos.
Outras dicas
O sucesso do desempenho vem da necessidade de uma verificação do tipo de tempo de execução. Se B é uma subclasse de A, quando você lançar A B em A A, você sabe no momento da compilação que será seguro, pois todos os Bs são como. Portanto, você não precisa gerar nenhum código de tempo de execução para verificar o tipo.
No entanto, quando você lançou um A em A B, você não sabe no momento da compilação se o A é realmente um B ou não. Pode ser apenas um A, pode ser do tipo C, um subtipo diferente de A. Portanto, você precisa gerar código de tempo de execução que garantirá que o objeto seja realmente um B e faça uma exceção, se não for.
Os genéricos não têm esse problema, porque o compilador sabe, no momento da compilação, que apenas o BS foi colocado na estrutura de dados; portanto, quando você puxa algo para fora, o compilador sabe que será um B, então não há necessidade de Tipo de verificação no tempo de execução.