Covariance vs. contravariance with respect to class inheritance

风流意气都作罢 提交于 2019-12-03 08:05:57

You have it backwards. You can add an Elephant to an Animal array because it is an Animal, and it's guaranteed to have all of the methods an Animal is required to have. You can't add an Animal to an Elephant array because it does not have all of the methods that an Elephant is required to have.

The Wikipedia article on covariance and contravariance has a good explanation of this:

Within the type system of a programming language, an operator from types to types is covariant if it preserves the ordering, ≤, of types, which orders types from more specific ones to more generic ones; it is contravariant if it reverses this ordering. If neither of these apply, the operator is invariant. These terms come from category theory.

Also, you said that type Elephant was "bigger", and this is not the case. Type Animal is "bigger" in the sense that it includes more specific types, such as Elephant, Giraffe, and Lion.

Have a look at this overview of covariance and contravariance in C# 4.0 and see if that helps:

http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx

You should try reading pages 45-49 of Introducing .NET 4.0 With Visual Studio 2010 which deals with this exact example. It even has some nice photos of elephants.

The main point to take out is, to do this

var things = new List<IThing<IContent>> { new ConcreteThing() }

with:

public class ConcreteThing : IThing<ConcreteContent>
{

}

you need the "out" in the interface definition, which will allow more specific forms to be set, but anything read out of IThing must be guaranteed to be the more general type.

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;
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!