Ковариация против контравариантности в отношении наследования классов

Что означают понятия «ковариация» и «контравариантность»?

Учитывая 2 класса, Animal и Elephant (который наследуется от Animal), я понимаю, что вы получите ошибки времени выполнения, если попытаетесь и поместите Elephant в массив Animals, и это происходит потому, что Elephant «больше» (точнее), чем Animal. Но не могли бы вы поместить Animal в массив Elephant, видя, как Elephant гарантированно содержит свойства Animal?


person alexmac    schedule 07.11.2008    source источник
comment
Полезно: blogs.msdn.com/ericlippert/archive/2007/10/16/   -  person    schedule 23.03.2010


Ответы (4)


У вас все наоборот. Вы можете добавить слона в массив Animal, потому что он является Animal, и у него гарантированно есть все методы, которые требуются для Animal. Вы не можете добавить Animal в массив Elephant, потому что у него нет всех методов, которые требуются от Elephant.

В статье Википедии о ковариации и контравариантности есть хорошее объяснение этого:

В системе типов языка программирования оператор перехода от типов к типам является ковариантным, если он сохраняет порядок, ≤, типов, который упорядочивает типы от более конкретных к более универсальным; он контравариантен, если он меняет этот порядок на противоположный. Если ничего из этого не применимо, оператор инвариантен. Эти термины взяты из теории категорий.

Кроме того, вы сказали, что тип Elephant был «больше», но это не так. Тип «Животное» «больше» в том смысле, что он включает в себя более конкретные типы, такие как слон, жираф и лев.

person Bill the Lizard    schedule 07.11.2008
comment
Ах, это имеет смысл, так можно ли сказать, что слон ковариантен животному, а животное контравариантно слону? - person alexmac; 07.11.2008
comment
Это зависит от того, что вы делаете с типами. Методы Elephant должны возвращать тот же или более узкий тип, что и методы Animal (они могут возвращать Animal или Elephant, если метод Animal возвращает Animal). Это можно было бы назвать ковариантным. - person Bill the Lizard; 07.11.2008
comment
Но параметры метода у методов Elephant должны быть такими же или более широкими, чем у методов Animal. Это контравариантность. - person Bill the Lizard; 07.11.2008

Взгляните на этот обзор ковариации и контравариантности в C # 4.0 и посмотрите, поможет ли это:

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

person MrKurt    schedule 07.11.2008

Вам следует попробовать прочитать страницы 45–49 в Знакомство с .NET 4.0 с Visual Studio 2010, в котором рассматривается именно этот пример. Там даже есть несколько красивых фотографий слонов.

Главное, что нужно вынести, - это сделать

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

с участием:

public class ConcreteThing : IThing<ConcreteContent>
{

}

вам нужен «выход» в определении интерфейса, который позволит устанавливать более конкретные формы, но все, что считывается из IThing, должно быть гарантированно более общего типа.

public interface IThing<out T> where T : IContent
{
}
person David    schedule 17.10.2012

введите описание изображения здесь

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;
person Hemendr    schedule 14.11.2018