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

StackOverflow https://stackoverflow.com/questions/272428

Вопрос

Каково значение понятий "ковариация" и "контравариантность"?

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

Это было полезно?

Решение

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

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

  

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

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

Другие советы

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

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

Вам следует попробовать прочитать страницы 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
{
}

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

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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top