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());
}
}
输出:
Method1Method2
正如您在上面的示例中所看到的,委托期望返回类型为 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());
}
输出:
Method1Method2
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