Covariância e Contravariância em C#, Parte Quatro: Variância de Delegate Real

04/01/2008 10:49:00 By Felipe Pessoto

Nos dois últimos artigos da série falei sobre dois tipos de variância que o C# suporta - covariância de array e covariância (nos tipos de retorno) e contravariância (nos tipos dos argumentos) na conversão de grupo de membros para delegate.

Hoje vamos generalizar este último tipo de variância.

Hoje no C# 3.0, embora seja válido atribuir um grupo de membros sem tipo para uma função que retorne uma Girafa para uma variável do tipo Func<Animal>, não é válido atribuir uma expressão tipada do tipo Func<Giraffe> para uma Func<Animal>. Tipos Generic do delegate são são sempre invariantes no C# 3.0. Isso parece fraco.

Suponha que nós temos a possibilidade de declarar os tipos dos parâmetros dos tipos generic do delegate como sendo covariante ou contravariante. Para simplificar (e manter a consistência com a notação existente nas especificações da CLR) iremos escrever os parâmetros de tipo covariante com um + e os parâmetros de tipo contravariantes com um -.

Esta não é uma notação muito atraente. Mas por enquanto vamos usá-la. A forma de se lembrar o que o + significa é "este tipo aceita tipos maiores na atribuição", e menores para o -.

Considere, por exemplo a nossa função padrão:

delegate R Func<A, R>(A a);

Desde que R apareça somente no retorno e A apareça somente na lista de parâmetros, podemos fazer do R covariante e o A contravariante:

delegate R Func< -A, +R >(A a);

Então novamente, você pode pensar nisto como "você pode fazer o A menor ou o R maior" (ou, é claro, ambos). Por exemplo:

Func<Animal, Giraffe> f1 = qualquer;

Func<Mammal, Mammal> f2 = f1;

Normalmente no C# esta atribuição será inválida porque os delegates são parametrizados por tipos diferentes. Mas desde que nós temos Func variante em ambos tipos de parâmetros, esta atribuição deveria se tornar válida para adicionar este tipo de variância à uma futura versão do C#.


Será que isto faz sentido até agora?

Esta regra nem sempre é correta! Algumas vezes o parâmetros de entrada precisa ser de um tipo de parâmetro covariante (no nosso exemplo A é contravariante). Iremos discutir isto somente no próximo artigo.


Comments (0)