O artigo trata de um novo recurso de conversão de tipos chamada variância. Essa conversão trata especificamente dos tipos genéricos do C#.
Em que situação o tema é útil
O recurso de variância facilita conversões no C#, permitindo que tipos base possam ser convertidos em genéricos, assim como os tipos genéricos poderão ser convertidos em tipos base, sem apresentar inconvenientes para o desenvolvedor.
Covariância e contravariância no C#
Neste artigo entenderemos o que é a variância, como ela já funcionava no C#. Aprenderemos para que serve com um exemplo prático desse recurso. No exemplo faremos comparações entre o recurso presente na versão 3.0 da linguagem e as novidades incorporadas na versão 4. Conheceremos um problema que se esconde nos arrays. Será simulada uma situação onde os arrays falham na hora de receber um determinado tipo, e porque eles são menos performáticos na hora de incluir um item. Outro item importante que será tratado são as aplicações e as exceções, ou seja, os tipos que agora aceitam esse recurso de conversão, mais especificamente, tipos genéricos como Interfaces e Delegates e os tipos em que não podemos aplicar a variância.
Durante o desenvolvimento de um software, muitas decisões são tomadas, muitos detalhes da arquitetura do projeto necessitam ser bem especificados e escritos, para que futuramente não tenhamos surpresas. A linguagem que utilizamos precisa estar em sincronia com as necessidades que surgem ao longo do tempo. Muitas funcionalidades são incorporadas à medida que a linguagem vai evoluindo, novos tipos são criados, novos recursos são adicionados, tudo isso para facilitar o desenvolvimento das aplicações e manutenções futuras.
Na versão 4.0 do C#, dentre algumas das novidades incorporadas, tivemos a adição de um recurso chamado de variância, algo que até então era contemplado pela linguagem de forma parcial e sujeita a um certo tipo de problema em determinadas situações.
Essa nova funcionalidade trata exatamente de como os tipos e subtipos podem ser convertidos de um tipo para outro. Mas o que vem a ser a variância? A variância é um termo que tem origem na matemática e define as relações de transformação entre elementos matemáticos de uma dada categoria para outra associando seus componentes/argumentos a fim de obter um novo elemento dentro das condições necessárias e de acordo com o tipo especificado.
Outro detalhe que precisamos deixar claro é que quando nos referimos ao termo variância, estamos falando de covariância e contravariância, ainda há também a invariância, que nesse caso como o nome já sugere, não há conversão de tipos. A partir da versão 4.0 o C# ganhou uma implementação mais robusta e segura para tratar de conversões. Até a versão 3.0 tínhamos apenas covariância e apenas em arrays, onde em determinadas situações, surge um problema relativo à segurança de tipos, que só ocorre em tempo de execução.
A partir da versão 4.0 a linguagem passou a contemplar a variância também em novos tipos como os Generics, mais especificamente estamos falando das Interfaces e os Delegates.
No .NET, o recurso de Generics em coleções aparece no namespace System.Collections.Generics. Neste namespace temos a implementação de várias classes que também são implementadas no namespace System.Collections.
A diferença é que a System.Collections.Generics permite a criação de coleções tipadas evitando as operações de casting (conversão), que são necessárias nas classes do namespace System.Collections.
Quando você programa com Generics, um dos primeiros conceitos que precisa assimilar é o type parameter. Este é o elemento base na declaração de qualquer tipo generic. O type parameter também é referido na documentação da Microsoft como type placeholder. Ele cria um local para que possamos informar qual é o argumento quando estamos criando uma instância de um tipo genérico. Sendo um dos elementos fundamentais para o uso de Generics, um type parameter tem uma série de regras associadas ao seu uso. A maioria destas regras está diretamente relacionada com o contexto em que o type parameter está sendo utilizado.