在接口方面,我不清楚C#中Covariance的概念。严格基于我下面的例子,这是协方差的一个例子,请描述原因或原因。
class Program
{
static void Main()
{
ICarInterface car = new Car();
}
}
interface ICarInterface
{
void Start();
}
class Car : ICarInterface
{
public void Start()
{
}
}
答案 0 :(得分:3)
协方差与子类型和泛型的相互作用有关。由于您的程序不涉及泛型,因此它不是协方差的示例。
如果U
是V
的子类型(例如U = Pear
和V = Fruit
),则通用类型G<T>
被称为协变如果T
是G<U>
的子类型,则G<V>
中的。例如,IEnumerable<Pear>
是IEnumerable<Fruit>
的子类型:您可以从中获取梨的东西可以用来取水果。
如果G
反转了子类型关系(G<V>
是G<U>
的子类型),则T
中的逆变。例如,Action<Fruit>
是Action<Pear>
的子类型:可以用来放入水果的东西可以用来放梨。
在您的示例中,ICarInterface
和Car
都没有可以协变的类型参数。
具体来说,在C#中,如果T
标有T
,则泛型类型在类型参数out
中是协变的。如果T
标有T
,则in
中存在逆变。
答案 1 :(得分:2)
不,这不是真正的协方差。这只是一个接口的实现。具体来说,它是赋值兼容性的一个示例。由于Car
类实现了ICarInterface
接口,因此可以将Car
对象分配给类型为ICarInterface
的变量。更具体类型(Car
)的对象被分配给存储区域以用于特定于较低类型(ICarInterface
),这可以起作用,因为这两种类型兼容用于分配。< / p>
协方差是一个稍微不同的东西。如果类型关系保留了类型的排序(从更具体到更通用),则它是协变的。例如,IEnumerable<T>
对于类型T
是协变的,因此它保留了类型IEnumerable<Vehicle>
(更通用)和IEnumerable<Car>
(更具体)的排序。 (在这个例子中,我们当然假设Car
是Vehicle
的子类)。
Eric Lippert has written an excellent article that distinguishes between covariance and assignment-compatibility。它有点技术性和理论性,但你一定要读它。我试着在这里进一步总结一下,我不会公正。
一个更容易理解的协方差的例子(至少在我看来)是返回型协方差。这是派生类重写基类方法返回更具体类型的地方。例如:
abstract class Habitat
{
public abstract Animal ApexPredator();
}
class Savanna : Habitat
{
public override Lion ApexPredator()
{ ... }
}
class Ocean : Habitat
{
public override Shark ApexPredator()
{ ... }
}
在此示例中,抽象类Habitat
有两个具体的子类:Savanna
和Ocean
。所有栖息地都有ApexPredator
,其类型为Animal
。但是在Savanna
对象中,顶点捕食者是Lion
,而在Ocean
对象中,顶点捕食者是Shark
。这是合法且安全的,因为Lion
和Shark
都是Animal
的类型。
不幸的是,C#不支持返回类型协方差。但是,它受到C ++(包括C ++ / CLI),Java和许多其他面向对象语言的支持。
答案 2 :(得分:0)
这不是协方差的一个例子,它只是多态性的一个简单例子。 Here你可以找到协方差和多态之间的差异