C# 中的协变和逆变
协变和逆变允许我们在处理类层次结构时保持灵活性。
在我们了解协变和逆变之前,请考虑以下类层次结构
示例:类层次结构
public class Small
{
}
public class Big: Small
{
}
public class Bigger : Big
{
}
根据上述示例类,small 是 big 的基类,big 是 bigger 的基类。这里要记住的一点是,派生类总是比基类多一些东西,所以基类相对比派生类小。
现在,考虑以下初始化

如上所示,基类可以容纳派生类,但派生类不能容纳基类。换句话说,如果要求 small,实例可以接受 big,但如果要求 big,则不能接受 small。
现在,让我们了解协变和逆变。
C# 中的协变
协变使您能够在预期基类型的地方传递派生类型。协变就像同种类的变体。基类和其他派生类被认为是同种类的类,它们为基类型添加了额外的功能。因此,协变允许您在预期基类的地方使用派生类(规则:如果预期 small,则可以接受 big)。
协变可以应用于委托、泛型、数组、接口等。
委托的协变
委托中的协变允许委托方法的返回类型具有灵活性。
示例:委托的协变
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());
}
}
输出
方法1方法2
如上例所示,委托期望返回类型为 small(基类),但我们仍然可以分配返回 Big(派生类)的 Method1 和与委托期望具有相同签名的 Method2。
因此,协变允许您将具有较少派生返回类型的方法分配给委托。
C# 逆变
逆变应用于参数。逆变允许将参数为基类的方法分配给期望参数为派生类的委托。
继续上面的例子,添加一个参数类型与委托不同的 Method3
示例:委托的逆变
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());
}
输出
方法1方法2
方法3
如您所见,Method3 的参数是 Small 类,而委托期望的参数是 Big 类。尽管如此,您仍然可以将 Method3 与委托一起使用。
您还可以像下面这样在同一方法中使用协变和逆变。
示例:协变和逆变
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());
}
}
输出
方法4