与C#和接口的协方差

时间:2016-06-19 12:38:02

标签: c# covariance

在接口方面,我不清楚C#中Covariance的概念。严格基于我下面的例子,这是协方差的一个例子,请描述原因或原因。

class Program
{
    static void Main()
    {
        ICarInterface car = new Car();
    }
}

interface ICarInterface
{
    void Start();
}

class Car : ICarInterface
{
    public void Start()
    {

    }
}

3 个答案:

答案 0 :(得分:3)

协方差与子类型和泛型的相互作用有关。由于您的程序不涉及泛型,因此它不是协方差的示例。

如果UV的子类型(例如U = PearV = Fruit),则通用类型G<T>被称为协变如果TG<U>的子类型,则G<V>中的。例如,IEnumerable<Pear>IEnumerable<Fruit>的子类型:您可以从中获取梨的东西可以用来取水果。

如果G反转了子类型关系(G<V>G<U>的子类型),则T中的逆变。例如,Action<Fruit>Action<Pear>的子类型:可以用来放入水果的东西可以用来放梨。

在您的示例中,ICarInterfaceCar都没有可以协变的类型参数。

具体来说,在C#中,如果T标有T,则泛型类型在类型参数out中是协变的。如果T标有T,则in中存在逆变。

答案 1 :(得分:2)

不,这不是真正的协方差。这只是一个接口的实现。具体来说,它是赋值兼容性的一个示例。由于Car类实现了ICarInterface接口,因此可以将Car对象分配给类型为ICarInterface的变量。更具体类型(Car)的对象被分配给存储区域以用于特定于较低类型(ICarInterface),这可以起作用,因为这两种类型兼容用于分配。< / p>

协方差是一个稍微不同的东西。如果类型关系保留了类型的排序(从更具体到更通用),则它是协变的。例如,IEnumerable<T>对于类型T是协变的,因此它保留了类型IEnumerable<Vehicle>(更通用)和IEnumerable<Car>(更具体)的排序。 (在这个例子中,我们当然假设CarVehicle的子类)。

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有两个具体的子类:SavannaOcean。所有栖息地都有ApexPredator,其类型为Animal。但是在Savanna对象中,顶点捕食者是Lion,而在Ocean对象中,顶点捕食者是Shark。这是合法且安全的,因为LionShark都是Animal的类型。

不幸的是,C#不支持返回类型协方差。但是,它受到C ++(包括C ++ / CLI),Java和许多其他面向对象语言的支持。

以下是更多concrete examples of covariance

答案 2 :(得分:0)

这不是协方差的一个例子,它只是多态性的一个简单例子。 Here你可以找到协方差和多态之间的差异