Ковариация против контравариантности в отношении наследования классов - PullRequest
5 голосов
/ 07 ноября 2008

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

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

Ответы [ 4 ]

9 голосов
/ 07 ноября 2008

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

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

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

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

2 голосов
/ 07 ноября 2008

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

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

0 голосов
/ 14 ноября 2018

enter image description here

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;
0 голосов
/ 17 октября 2012

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

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

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

с:

public class ConcreteThing : IThing<ConcreteContent>
{

}

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

public interface IThing<out T> where T : IContent
{
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...