关于类继承的协方差与逆变
-
07-07-2019 - |
题
概念'协方差'和'逆变'是什么意思?
鉴于2个类, Animal 和 Elephant (继承自 Animal ),我的理解是您会遇到运行时错误如果你试图将一只大象放入一系列动物中,这就发生了,因为大象是“更大”的。 (比较具体)比动物。但是你可以将动物放入大象阵列中,看看大象是如何保证包含动物属性的吗?
解决方案
你倒退了。您可以将Elephant添加到Animal数组中,因为它是 Animal,并且它保证拥有Animal所需的所有方法。您无法将Animal添加到Elephant数组中,因为它不具有Elephant所需的所有方法。
关于协方差和逆变的维基百科文章对此有一个很好的解释:
在编程语言的类型系统中,从类型到类型的运算符是协变的,如果它保留了类型的排序,它将类型从更具体的类型排序到更通用的类型;如果它颠倒了这种顺序,它就是逆变的。如果这些都不适用,则运算符是不变的。这些术语来自范畴理论。
另外,你说大象的类型是“更大”,而事实并非如此。类型动物是“更大”的从某种意义上说,它包括更具体的类型,如大象,长颈鹿和狮子。
其他提示
您应该尝试阅读使用Visual Studio 2010引入.NET 4.0的第45-49页处理这个确切的例子。它甚至还有一些很好的大象照片。
要取出的主要观点是,
var things = new List<IThing<IContent>> { new ConcreteThing() }
使用:
public class ConcreteThing : IThing<ConcreteContent>
{
}
你需要“出去”在接口定义中,这将允许设置更具体的表单,但必须保证从IThing中读取的任何内容都是更通用的类型。
public interface IThing<out T> where T : IContent
{
}
public interface IGoOut<out T>
{
T Func();
}
public interface IComeIn<in T>
{
void Action(T obj);
}
public class GoOutClass<T>:IGoOut<T>
{
public T Func()
{
return default(T);
}
}
public class ComeInClass<T> : IComeIn<T>
{
public void Action(T obj) { }
}
==========================================================
object obj = null;
//Covariance Example [Array + IEnumerable<T> + IEnumerator<T> + IInterface<Out T> + Func<T>]
object[] array = (string[]) obj;
IEnumerable<object> enumerable = (IEnumerable<string>) obj;
IEnumerator<object> enumerator = (IEnumerator<string>)obj;
IGoOut<object> goOut = (GoOutClass<string>)obj;
Func<object> func = (Func<string>)obj;
//Contravariance Example[IInterface<in T>]
IComeIn<string> comeIn = (ComeInClass<object>) obj;
不隶属于 StackOverflow