协变和逆变使我们在处理类层次结构时更加灵活。
在学习协变和逆变之前,请看以下类层次结构:
public class Small { } public class Big: Small { } public class Bigger : Big { }
根据上面的示例类,Small 是 Big 的基类,而Big 是 Bigger 的基类。这里要记住的一点是,派生类将始终具有比基类更多的东西,因此基类比派生类要小。
现在,看以下初始化:
如上所示,基类可以容纳派生类,但派生类不能容纳基类。换句话说,一个实例即使要求很小也可以接受大,但是如果要求很大就不能接受小。
现在,让我们了解协变和逆变。
协变使您能够传递派生类型,其中需要基类型。协变就像同类型的方差。基类和其他派生类被认为是向基类型添加额外功能的同类类。因此,协变允许您在需要基类的地方使用派生类(如果需要小类,则 rule: 可以接受大类)。
协变可以应用于委托,泛型,数组,接口等。
委托中的协变允许委托方法的返回类型具有灵活性。
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(基类),但是我们仍然可以分配返回Big(派生类)的Method1以及具有与委托期望的签名相同的Method2。
因此,协变允许您将方法分配给具有较少派生返回类型的委托。
将Contravariane(逆变)应用于参数。 Cotravariance(逆变) 允许将基类参数分配给希望派生类参数的委托的方法。
继续上面的示例,添加具有与委托不同的参数类型的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()); }
Method1 Method2 Method3
如您看到的,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()); } }
Method4