Я смотрел видео об этом на 9-м канале, но я этого не очень-то понял.
Может кто-нибудь, пожалуйста, дайте мне простой пример об этом, который легко понять? После этого возможно, как это будет использоваться на практике?
Я смотрел видео об этом на 9-м канале, но я этого не очень-то понял.
Может кто-нибудь, пожалуйста, дайте мне простой пример об этом, который легко понять? После этого возможно, как это будет использоваться на практике?
Возможно, вы захотите посмотреть на этот блог, он делает фантастическую работу по его объяснению, но я думаю, что это потребует больше примеров, чтобы прояснить это для людей, поскольку это попадает в очень трудную для понимания область, но, приведенная ниже цитата из статьи суммирует ее хорошо.
http://hestia.typepad.com/flatlander/2008/12/c-covariance-and-contravariance-by-example.html
"ковариация и контравариантность" означает что теперь вы можете пройти неточно когда это безопасно, так же, как и вы можете передавать неточные типы аргументов когда это безопасно.
A Tiger
IS a Animal
, поэтому он может делать все, что может сделать Animal
. Если у меня есть метод, который запрашивает Animal
, я также могу передать Tiger
.
Ковариация. Передача более специфического аргумента типа
Это направление, с которым вы больше всего знакомы. Я могу передать IEnumerable<Tiger>
в любом месте, ожидая IEnumerable<Animal>
.
static void ListAnimals(IEnumerable<Animal> animals)
{
}
List<Tiger> tigers = new List<Tiger>();
ListAnimals(tigers);
Контравариантность. Передача более общего аргумента типа.
"contra" подразумевает, что это идет "против" нормального потока конверсии. Это сложнее, потому что это кажется противоречивым, пока вы не увидите его в действии.
Скажем, у меня есть функция, которая ожидает сравнения IComparer<Tiger>
и двух тигров. Контравариантность говорит, что я могу также перейти к более общим IComparer<Animal>
, потому что он также может сравнивать двух тигров (так как Тигр - это животное). Он сравнивает их более общим образом, но это по-прежнему безопасно.
static void CompareTigers(IComparer<Tiger> comparer, Tiger tiger1, Tiger tiger2)
{
comparer.Compare(tiger1, tiger2);
}
// normal - a tiger comparer can compare two tigers
IComparer<Tiger> tigerComparer = null;
CompareTigers(tigerComparer, new Tiger(), new Tiger());
// contravariance - an animal comparer can ALSO compare two tigers
IComparer<Animal> animalComparer = null;
CompareTigers(animalComparer, new Tiger(), new Tiger());
Обратите внимание, что это также работает с делегатами. Я могу передать Action<Animal>
в функцию, ожидающую Action<Tiger>
, потому что объекты Tiger
также могут быть переданы делегату Action<Animal>
.
Эрик Липперт придумал очень хорошее объяснение в недавнем сообщении
Следующая статья посвящена совместной и контравариантности с делегатами: http://msdn.microsoft.com/en-us/library/ms173174.aspx.
Возможно, вам это полезно, даже если вы еще не участвуете в делегатах. Я понял, что это очень легко понять.
Документы MSDN для С# 4.0 (и VB) находятся здесь: Ковариация и контравариантность
Если вас интересуют конкретные примеры, они находятся здесь: