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ê?

Foi útil?

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.

Lendo no IL que é gerado (este artigo menciona) ... aha - isinst.

Se você não estivesse abatido, não precisaria ligar isinst.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top