English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

C# Covariância e Contravariância

A covariância e contravariância nos tornam mais flexíveis ao lidar com hierarquias de classes.

Antes de aprender sobre covariância e contravariância, veja a seguinte hierarquia de classes:

public class Small
{ 
}
public class Big: Small
{
}
public class Bigger : Big
{ 
    
}

De acordo com o exemplo de classe acima, Small é a classe base de Big e Big é a classe base de Bigger. Algo a lembrar aqui é que a classe derivada sempre terá mais coisas do que a classe base, portanto, a classe base é menor do que a classe derivada.

Agora, veja a inicialização a seguir:

Inicialização de classe

Como mostrado acima, a classe base pode conter classes derivadas, mas as classes derivadas não podem conter a classe base. Em outras palavras, um instância mesmo que exigida pequena pode aceitar grande, mas se exigida grande não pode aceitar pequena.

Agora, vamos entender a covariância e contravariância.

C# Covariância (Covariance)

A covariância permite que você passe tipos derivados, onde é necessária a tipo base. A covariância é como a variação do mesmo tipo. A classe base e outras classes derivadas são consideradas classes do mesmo tipo que adicionam funcionalidades adicionais ao tipo base. Portanto, a covariância permite que você use classes derivadas onde é necessária a classe base (se necessário o subtipo, a regra: pode aceitar o super tipo).

A covariância pode ser aplicada a delegações, genéricos, arrays, interfaces, etc.

Covariância de delegação

A covariância na delegação permite que o tipo de retorno do método da delegação seja flexível.

public delegate Small covarDel(Big mc);
public class Program
{
    public static Big Method1(Big bg)
    {
        Console.WriteLine("Method1);
    
        return new Big();
    }
    public static Small Method2(Big bg)
    {
        Console.WriteLine("Method2);
    
        return new Small();
    }
        
    public static void Main(string[] args)
    {
        covarDel del = Method1;
        Small sm1 = del(new Big());
        del = Method2;
        Small sm2 = del(new Big());
    }
}
Saída:
Método1
Método2

Como você vê no exemplo acima, o delegado espera o tipo de retorno Small (classe base), mas ainda podemos atribuir Method que retorna Big (classe derivada)1e Method com a assinatura igual à esperada pelo delegado2.

Portanto, a covariância permite que você atribua métodos a delegações com tipos de retorno de menor derivação.

Contravariância no C#

Aplicar Contravariance (contravariância) aos parâmetros. A contravariância permite atribuir parâmetros de classe base a métodos de delegação que esperam parâmetros de classe derivada.

Continuando com o exemplo anterior, adicione um Method com tipo de parâmetro diferente do delegado.3:

delegate Small covarDel(Big mc);
class Program
{
    static Big Method1(Big bg)
    {
        Console.WriteLine("Method1);
        return new Big();
    }
    static Small Method2(Big bg)
    {
        Console.WriteLine("Method2);
        return new Small();
    }
    static Small Method3(Small sml)
    {
        Console.WriteLine("Method3);
        
        return new Small();
    }
    static void Main(string[] args)
    {
        covarDel del = Method1;
        del += Method2;
        del += Method3;
        Small sm = del(new Big());
}
Saída:
Método1
Método2
Método3

Como você vê, Method3Com parâmetro da classe Small, enquanto o delegado espera parâmetro da classe Big. No entanto, você pode atribuir Method3Usando com delegação.

Você também pode usar covariância e contravariância da mesma forma que mostrado a seguir.

Exemplo: uso de covariância e contravariância
delegar Small covarDel(Big mc); classe Program
{            static Big Method4(Small sml)
    {            Console.WriteLine("Method3);    
        return new Big();
    }            static void Main(string[] args)
    {            covarDel del = Method4;    
        Small sm = del(new Big());
    }
}
Saída:
Método4