Covariance and Contravariance in C#

本文关键字:in Contravariance and Covariance | 更新日期: 2023-09-12 17:38:48

协方差和逆变使我们能够在处理类层次结构时保持灵活性。

在我们了解协方差和逆变之前,请考虑以下类层次结构:

Example: Class Hierarchy

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

根据上面的示例类,small 是 big 的基类,big 是 big 的基类。这里要记住的一点是,派生类将始终具有比基类更多的东西,因此基类相对小于派生类。

现在,考虑以下初始化:

class 初始化

如上所示,基类可以保存派生类

,但派生类不能保存基类。换句话说,一个实例即使要求小也可以接受大,但如果它要求大,它就不能接受小。

现在,让我们了解协方差和逆变。

C# 中的协方差

协方差使您能够在需要基类型的位置传递派生类型。协方差类似于同类方差。基类和其他派生类被视为向基类型添加额外功能的同一类。因此,协方差允许您使用派生类,其中需要基类(规则:如果预期较小,则可以接受大)。

协方差可以应用于委托、泛型、数组、接口等。

与委托的协方差

委托中的协方差允许委托方法的返回类型具有灵活性。

Example: Covariance with Delegate

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());
    }
}

输出:

Method1
Method2

正如您在上面的示例中所看到的,委托期望返回类型为 small(基类),但我们仍然可以分配返回 Method1(派生类)和与委托期望具有相同签名的 Method2。

因此,协方差允许您将方法分配给具有较少派生返回类型的委托。

C# Contravariance

逆变应用于参数。逆变允许将具有基类参数的方法分配给需要派生类参数的委托。

继续上面的示例,添加参数类型与委托不同的 Method3:

Example: Contravariance with Delegate

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());
}

输出:

Method1
Method2
Method3

如您所见,Method3 的参数为 Small class,而委托需要一个 Big class 的参数。不过,您可以将 Method3 与委托一起使用。

您还可以在如下所示的相同方法中使用协方差和逆变。

Example: Covariance and Contravariance

delegate Small covarDel(Big mc);
class 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());
    }
}

输出:

Method4